akiran / akiran/react-slick

React error #130 when bundled by Vite 8 / rolldown: default import is the CJS namespace, not the Slider class

Abierto
#2,444 2 comentarios 9 reacciones 0 asignados Ver en GitHub
Lenguaje dominante
JavaScript
Estrellas
11.9k
Forks
2.1k
Métricas de merge de PR
Sin PR fusionados en 30 d

Descripción

## Description

When a React app with `"type": "module"` in its `package.json` is bundled by **Vite 8** (which ships [rolldown](https://rolldown.rs/) as its bundler), `import Slider from 'react-slick'` resolves to the CJS namespace object `{default: Slider, __esModule: true}` at runtime — **not** the `Slider` class. Any `` render site then receives an object as its component type and throws:

```
Uncaught Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
```

(minified: `React error #130; visit https://react.dev/errors/130?args[]=object&args[]=`)

## Root cause

`lib/index.js` ends with:

```js
exports["default"] = void 0;
var _slider = _interopRequireDefault(require("./slider"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
var _default = exports["default"] = _slider["default"];
```

It sets `exports.default` and flags `__esModule: true`, but it never re-assigns `module.exports = exports["default"]`. When the consumer is flagged `"type": "module"`, rolldown follows Node's ESM-for-CJS convention and treats the default import as `module.exports` itself, which is the whole namespace `{default: Slider, __esModule: true}` — not the class.

This is documented / intentional behavior on rolldown's side:
- https://rolldown.rs/in-depth/bundling-cjs#ambiguous-default-import-from-cjs-modules
- [rolldown/rolldown#8061](https://github.com/rolldown/rolldown/issues/8061) (closed as "expected behavior")

The de-facto workaround in the ecosystem is for the CJS package itself to re-export its default on `module.exports` — e.g. `react-modal`'s own `lib/index.js` ends with:

```js
module.exports = exports["default"];
```

So `module.exports` equals the class at runtime regardless of which CJS-default-import heuristic the bundler picks. `react-slick` does not do this, which is why it breaks specifically under Vite 8.

## Reproduction

Minimal setup (any Vite 8 project with `"type": "module"` works):

```tsx
// src/main.tsx
import 'slick-carousel/slick/slick.css';
import 'slick-carousel/slick/slick-theme.css';
import Slider from 'react-slick';
import { createRoot } from 'react-dom/client';

console.log('typeof Slider =', typeof Slider); // 'object' under vite 8 — should be 'function'

createRoot(document.getElementById('root')!).render(

slide 1

slide 2


);
```

```json
// package.json excerpt
{
"type": "module",
"dependencies": {
"react": "19.2.5",
"react-dom": "19.2.5",
"react-slick": "0.31.0",
"slick-carousel": "1.8.1",
"vite": "8.0.8"
}
}
```

```
$ pnpm build && pnpm preview
# open http://localhost:4173
# Console: Uncaught Error: Minified React error #130; ... args[]=object
```

Reproduces under **Vite 8.0.x** (rolldown). Works fine under Vite 7.x (pre-rolldown) and under webpack / Rollup / esbuild in every configuration I've tested.

## Suggested fix

The compiled entry should end up with `module.exports` pointing at the `Slider` class directly, matching what `react-modal`'s own compiled output does. Two equivalent ways to get there — **PR #2445** uses the first:

**1. Source-level (proposed in #2445)** — in `src/index.js`:

```diff
import Slider from "./slider";

-export default Slider;
+module.exports = Slider;
+module.exports.default = Slider;
```

After `@babel/preset-env` compiles, `lib/index.js` ends up as:

```js
"use strict";
var _slider = _interopRequireDefault(require("./slider"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
module.exports = _slider["default"];
module.exports["default"] = _slider["default"];
```

No new dependency, no build-config change.

**2. Babel-plugin alternative** — keep `src/index.js` as `export default Slider;` and add [`babel-plugin-add-module-exports`](https://github.com/59naga/babel-plugin-add-module-exports) to `.babelrc`:

```diff
"plugins": [
- "@babel/plugin-proposal-class-properties"
+ "@babel/plugin-proposal-class-properties",
+ "add-module-exports"
]
```

That plugin is widely used for this exact interop fix but hasn't had a release since 2019, which is why I went with the source-level approach in #2445. Either works functionally.

## Workaround for consumers today

For pnpm users:

```jsonc
// package.json
"pnpm": {
"patchedDependencies": {
"react-slick@0.31.0": "patches/react-slick@0.31.0.patch"
}
}
```

```
# patches/react-slick@0.31.0.patch
diff --git a/lib/index.js b/lib/index.js
--- a/lib/index.js
+++ b/lib/index.js
@@ -7,3 +7,4 @@
var _slider = _interopRequireDefault(require("./slider"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
var _default = exports["default"] = _slider["default"];
+module.exports = exports["default"];
```

For npm/yarn users, the equivalent with [`patch-package`](https://github.com/ds300/patch-package).

Guía de contribución

Abrir la guía de contribución

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.