akiran / akiran/react-slick

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

オープン
#2,444 コメント 2 件 リアクション 9 件 担当者 0 名 GitHub で見る
主要言語
JavaScript
スター
11.9k
フォーク
2.1k
PR マージ指標
30日以内にマージされた PR はありません

説明

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

コントリビューションガイド

コントリビューションガイドを開く

評価

この issue はまだ評価されていません。

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。