akiran / akiran/react-slick

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

Đang mở
#2,444 2 bình luận 9 reaction 0 người được giao Xem trên GitHub
Ngôn ngữ chính
JavaScript
Star
11.9k
Fork
2.1k
Chỉ số merge pull request
Không có pull request nào được merge trong 30 ngày

Mô tả

## 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).

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.