示例
@rollup/plugin-commonjs 28.0.7: By default @rollup/plugin-commonjs renders external requires as default imports causing named exports to be inaccessible unless esmExternals is configured
已验证示例 — npm @rollup/plugin-commonjs 28.0.7: By default @rollup/plugin-commonjs renders external requires as default imports causing named exports to be…
sha256:4c5bf847bf0aa98a1bfd3b9919628d6ee74bd297513afb48edef8f7e4b2feb30
本网络只提供一件事:能构建的样本。它在沙箱中运行并保留签名回执。它不评级、不担保——同样的代码能否在你的环境构建,它没有测量过。
提交了通过的契约回执的不同签名密钥数量。为 1 表示只有作者;大于 1 表示还有其他人构建过。密钥是自行生成的,背后没有注册身份,因此计的是密钥而非人。
MIT-0
执行证据
声明的环境与签名的运行分开呈现,你可以看到这个样本究竟运行了什么、在哪里运行。
- 证据依据
- 签名契约通过
- 验证回执
- 1
- 构建过它的签名密钥
- 1
声明的环境
node linux 24 · ubuntu · glibc 2.39 x64 node node npm
验证运行环境
| 环境 | 契约 | 阶段 | 运行日期 |
|---|---|---|---|
| node 22 · linux debian/x64 · docker ed25519:c1973797be207ac4 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · node-typescript@1node:22@sha256:8a34c4ab3ea2… |
2026-09-03 |
案例
HOW- 目标
- By default @rollup/plugin-commonjs renders external requires as default imports causing named exports to be inaccessible unless esmExternals is configured
- 符号
-
- commonjs
- esmExternals
- 环境
- node
- 创建时间
- 2026-09-03T09:28:03Z
契约
- assert @rollup/plugin-commonjs with default esmExternals: false emits default imports for external dependencies, causing named exports to be inaccessible (undefined) when required from CommonJS
- assert setting esmExternals: true emits namespace imports for external dependencies, creating an augmented namespace that exposes both named exports and default export
- assert esmExternals accepts an array of package IDs to selectively emit namespace imports for specified ESM dependencies while leaving other externals as default imports
- assert esmExternals accepts a predicate function to dynamically determine which external dependencies are imported as ES module namespaces
文件
- NOTES.md
- PROMPT.md
- csx.json
- package-lock.json
- package.json
- spec.json
- test/contract.mjs
源代码
# Notes: Rollup CommonJS Plugin External ES Modules and esmExternals
## Search Result
`search_known_solution` returned `NO_SAFE_MATCH` for `@rollup/plugin-commonjs@28.0.7` with symbol `esmExternals`. Existing verified samples for this package covered `strictRequires`, `requireReturnsDefault`, and `transformMixedEsModules`, but none demonstrated how external dependencies are handled when required from CommonJS.
## Naive Model Assumption
A developer or coding model assumes that requiring an external ES module from a CommonJS module bundled with `@rollup/plugin-commonjs` preserves access to all exported symbols, including named exports (such as `const { helper } = require('external-pkg')`).
## Failure Mode
By default (`esmExternals: false`), `@rollup/plugin-commonjs` assumes all external dependencies are CommonJS and generates an unknown require proxy that emits only a default import (`export { default } from 'external-pkg'`). When the external ES module defines named exports, attempting to access them in CommonJS evaluates to `undefined`, causing silent functional failures or runtime `TypeError` when calling functions. Enabling `esmExternals: true` (or passing an array of IDs or a predicate function) switches the proxy to import the ES module namespace and wraps it in an augmented namespace, making both named exports and default exports accessible.
Clean-room public code sample — generation instructions
Write a brand-new, minimal, self-contained code sample in this clean-room directory.
Do not copy, paraphrase, or reference any existing project source. Work only from this spec.
A csx.json manifest scaffold already exists. Do not recreate it from memory. Preserve its case.goal, packages and symbols; fill its empty case.contract with exact assertions and correct its environment, commands and verifierAdapter for the files you generate.
Goal: By default @rollup/plugin-commonjs renders external requires as default imports causing named exports to be inaccessible unless esmExternals is configured
Kind: HOW
Use EXACTLY these public packages and versions:
- pkg:npm/%40rollup/plugin-commonjs@28.0.7
- pkg:npm/rollup@4.34.8
Demonstrate these symbols/APIs:
- commonjs
- esmExternals
Rules:
- One focused purpose; the smallest project that proves the goal.
- Include a contract test (test/contract.*) that runs OFFLINE and exits 0 exactly when the goal behavior works.
- Pin every dependency with a lockfile so resolution is reproducible.
- No secrets, credentials, or tokens. No real URLs (only example.com or localhost). No absolute paths.
- No personal names, emails, company names, or project identifiers of any kind.
- No binaries and no generated output (node_modules, dist, target, venv, .git, .env).
- Keep it under 200 files and 256KB packed.
{"case":{"believed":"By default @rollup/plugin-commonjs allows CommonJS modules requiring external ES modules to access both default and named exports.","caseId":"case:sha256:042d2e62034055b487fd659dbd694e3a334e373ef1364a7caa266f6bcb694717","contract":["assert @rollup/plugin-commonjs with default esmExternals: false emits default imports for external dependencies, causing named exports to be inaccessible (undefined) when required from CommonJS","assert setting esmExternals: true emits namespace imports for external dependencies, creating an augmented namespace that exposes both named exports and default export","assert esmExternals accepts an array of package IDs to selectively emit namespace imports for specified ESM dependencies while leaving other externals as default imports","assert esmExternals accepts a predicate function to dynamically determine which external dependencies are imported as ES module namespaces"],"goal":"By default @rollup/plugin-commonjs renders external requires as default imports causing named exports to be inaccessible unless esmExternals is configured","kind":"HOW","packages":["pkg:npm/%40rollup/plugin-commonjs@28.0.7","pkg:npm/rollup@4.34.8"],"schemaVersion":1,"symbols":["commonjs","esmExternals"]},"contractCommand":["node","test/contract.mjs"],"environment":{"arch":"x64","distro":"ubuntu","ecosystem":"npm","executionContext":"node","language":"node","libc":"glibc","libcVersion":"2.39","os":"linux","osVersionBucket":"24","packageManager":"npm","runtime":"node","schemaVersion":1},"license":"MIT-0","packages":["pkg:npm/%40rollup/plugin-commonjs@28.0.7","pkg:npm/rollup@4.34.8"],"schemaVersion":1,"symbols":["commonjs","esmExternals"],"verifierAdapter":"node-typescript@1"}
{
"name": "npm-rollup-plugin-commonjs-esm-externals",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "npm-rollup-plugin-commonjs-esm-externals",
"version": "1.0.0",
"license": "MIT-0",
"dependencies": {
"@rollup/plugin-commonjs": "28.0.7",
"rollup": "4.34.8"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz",
"integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==",
"license": "MIT"
},
"node_modules/@rollup/plugin-commonjs": {
"version": "28.0.7",
"resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.7.tgz",
"integrity": "sha512-6cE2Wr/MkpdtTS8gXlCn9Zdmf7e9Xm96yFqOwFEXuvYLAHtjRf57/n6GEVF4K8NSesT1eKdBtcDA/SQdpW/8nA==",
"license": "MIT",
"dependencies": {
"@rollup/pluginutils": "^5.0.1",
"commondir": "^1.0.1",
"estree-walker": "^2.0.2",
"fdir": "^6.2.0",
"is-reference": "1.2.1",
"magic-string": "^0.30.3",
"picomatch": "^4.0.2"
},
"engines": {
"node": ">=16.0.0 || 14 >= 14.17"
},
"peerDependencies": {
"rollup": "^2.68.0||^3.0.0||^4.0.0"
},
"peerDependenciesMeta": {
"rollup": {
"optional": true
}
}
},
"node_modules/@rollup/pluginutils": {
"version": "5.4.0",
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.4.0.tgz",
"integrity": "sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==",
"license": "MIT",
"dependencies": {
"@types/estree": "^1.0.0",
"estree-walker": "^2.0.2",
"picomatch": "^4.0.2"
},
"engines": {
"node": ">=14.0.0"
},
"peerDependencies": {
"rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
},
"peerDependenciesMeta": {
"rollup": {
"optional": true
}
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.8.tgz",
"integrity": "sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw==",
"cpu": [
"arm"
],
"license": "MIT",
"optional": true,
"os": [
"android"
]
},
"node_modules/@rollup/rollup-android-arm64": {
"version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.8.tgz",
"integrity": "sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"android"
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.8.tgz",
"integrity": "sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@rollup/rollup-darwin-x64": {
"version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.8.tgz",
"integrity": "sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.8.tgz",
"integrity": "sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"freebsd"
]
},
"node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.8.tgz",
"integrity": "sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"freebsd"
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.8.tgz",
"integrity": "sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g==",
"cpu": [
"arm"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.8.tgz",
"integrity": "sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA==",
"cpu": [
"arm"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.8.tgz",
"integrity": "sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.8.tgz",
"integrity": "sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
"version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.8.tgz",
"integrity": "sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ==",
"cpu": [
"loong64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
"version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.8.tgz",
"integrity": "sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw==",
"cpu": [
"ppc64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.8.tgz",
"integrity": "sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw==",
"cpu": [
"riscv64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.8.tgz",
"integrity": "sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA==",
"cpu": [
"s390x"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.8.tgz",
"integrity": "sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.8.tgz",
"integrity": "sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.8.tgz",
"integrity": "sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.8.tgz",
"integrity": "sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w==",
"cpu": [
"ia32"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.8.tgz",
"integrity": "sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@types/estree": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz",
"integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==",
"license": "MIT"
},
"node_modules/commondir": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
"integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
"license": "MIT"
},
"node_modules/estree-walker": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
"license": "MIT"
},
"node_modules/fdir": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
"license": "MIT",
"engines": {
"node": ">=12.0.0"
},
"peerDependencies": {
"picomatch": "^3 || ^4"
},
"peerDependenciesMeta": {
"picomatch": {
"optional": true
}
}
},
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/is-reference": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz",
"integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==",
"license": "MIT",
"dependencies": {
"@types/estree": "*"
}
},
"node_modules/magic-string": {
"version": "0.30.21",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
"integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
"license": "MIT",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.5"
}
},
"node_modules/picomatch": {
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz",
"integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==",
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/rollup": {
"version": "4.34.8",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.8.tgz",
"integrity": "sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ==",
"license": "MIT",
"dependencies": {
"@types/estree": "1.0.6"
},
"bin": {
"rollup": "dist/bin/rollup"
},
"engines": {
"node": ">=18.0.0",
"npm": ">=8.0.0"
},
"optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.34.8",
"@rollup/rollup-android-arm64": "4.34.8",
"@rollup/rollup-darwin-arm64": "4.34.8",
"@rollup/rollup-darwin-x64": "4.34.8",
"@rollup/rollup-freebsd-arm64": "4.34.8",
"@rollup/rollup-freebsd-x64": "4.34.8",
"@rollup/rollup-linux-arm-gnueabihf": "4.34.8",
"@rollup/rollup-linux-arm-musleabihf": "4.34.8",
"@rollup/rollup-linux-arm64-gnu": "4.34.8",
"@rollup/rollup-linux-arm64-musl": "4.34.8",
"@rollup/rollup-linux-loongarch64-gnu": "4.34.8",
"@rollup/rollup-linux-powerpc64le-gnu": "4.34.8",
"@rollup/rollup-linux-riscv64-gnu": "4.34.8",
"@rollup/rollup-linux-s390x-gnu": "4.34.8",
"@rollup/rollup-linux-x64-gnu": "4.34.8",
"@rollup/rollup-linux-x64-musl": "4.34.8",
"@rollup/rollup-win32-arm64-msvc": "4.34.8",
"@rollup/rollup-win32-ia32-msvc": "4.34.8",
"@rollup/rollup-win32-x64-msvc": "4.34.8",
"fsevents": "~2.3.2"
}
},
"node_modules/rollup/node_modules/@types/estree": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
"integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
"license": "MIT"
}
}
}
{
"name": "npm-rollup-plugin-commonjs-esm-externals",
"version": "1.0.0",
"license": "MIT-0",
"type": "module",
"scripts": {
"test": "node test/contract.mjs"
},
"dependencies": {
"@rollup/plugin-commonjs": "28.0.7",
"rollup": "4.34.8"
}
}
{
"schemaVersion": 1,
"goal": "By default @rollup/plugin-commonjs renders external requires as default imports causing named exports to be inaccessible unless esmExternals is configured",
"kind": "HOW",
"packages": [
"pkg:npm/%40rollup/plugin-commonjs@28.0.7",
"pkg:npm/rollup@4.34.8"
],
"symbols": [
"commonjs",
"esmExternals"
]
}
import assert from 'node:assert/strict';
import { rollup } from 'rollup';
import commonjs from '@rollup/plugin-commonjs';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const projectRoot = path.resolve(__dirname, '..');
async function runContract() {
const mockModuleDir = path.join(projectRoot, 'node_modules', 'mock-external-esm');
fs.mkdirSync(mockModuleDir, { recursive: true });
fs.writeFileSync(
path.join(mockModuleDir, 'package.json'),
JSON.stringify({
name: 'mock-external-esm',
version: '1.0.0',
type: 'module',
exports: './index.js'
})
);
fs.writeFileSync(
path.join(mockModuleDir, 'index.js'),
`export const version = '1.0.0';
export const helper = function() { return 'helped'; };
export default { defaultKey: 'defaultValue' };`
);
const mockOtherDir = path.join(projectRoot, 'node_modules', 'mock-other-pkg');
fs.mkdirSync(mockOtherDir, { recursive: true });
fs.writeFileSync(
path.join(mockOtherDir, 'package.json'),
JSON.stringify({
name: 'mock-other-pkg',
version: '1.0.0',
main: './index.js'
})
);
fs.writeFileSync(
path.join(mockOtherDir, 'index.js'),
`module.exports = { otherVal: 'from-other-cjs' };`
);
const virtualEntry = {
name: 'virtual-entry',
resolveId(id) {
if (id === 'entry-cjs.cjs') return id;
},
load(id) {
if (id === 'entry-cjs.cjs') {
return `
const ext = require('mock-external-esm');
const other = require('mock-other-pkg');
module.exports = { ext, other };
`;
}
}
};
const tmpFiles = [];
try {
// -------------------------------------------------------------------------
// Contract Assertion 1:
// By default (esmExternals: false), @rollup/plugin-commonjs treats external
// dependencies as CommonJS default imports, causing named exports from
// external ES modules to be inaccessible (undefined) when required from CommonJS.
// -------------------------------------------------------------------------
const defaultBundle = await rollup({
input: 'entry-cjs.cjs',
external: ['mock-external-esm', 'mock-other-pkg'],
plugins: [virtualEntry, commonjs()]
});
const { output: defaultOutput } = await defaultBundle.generate({ format: 'es' });
const defaultCode = defaultOutput[0].code;
assert.match(
defaultCode,
/import\s+require\$\$\d+\s+from\s+['"]mock-external-esm['"];/,
'assert @rollup/plugin-commonjs with default esmExternals: false emits default imports for external dependencies, causing named exports to be inaccessible (undefined) when required from CommonJS'
);
const tmpDefault = path.join(projectRoot, '.tmp-contract-default.mjs');
tmpFiles.push(tmpDefault);
fs.writeFileSync(tmpDefault, defaultCode);
const modDefault = (await import(`file://${tmpDefault.replace(/\\/g, '/')}`)).default;
assert.equal(
typeof modDefault.ext.helper,
'undefined',
'Named export is undefined when required from CommonJS under default esmExternals: false'
);
assert.equal(
modDefault.ext.defaultKey,
'defaultValue',
'Default export remains accessible through default import proxy'
);
// -------------------------------------------------------------------------
// Contract Assertion 2:
// Setting esmExternals: true renders external dependencies as namespace
// imports wrapped in an augmented namespace, exposing both named and default exports.
// -------------------------------------------------------------------------
const esmBundle = await rollup({
input: 'entry-cjs.cjs',
external: ['mock-external-esm', 'mock-other-pkg'],
plugins: [virtualEntry, commonjs({ esmExternals: true })]
});
const { output: esmOutput } = await esmBundle.generate({ format: 'es' });
const esmCode = esmOutput[0].code;
assert.match(
esmCode,
/import\s+\*\s+as\s+mockExternalEsm\s+from\s+['"]mock-external-esm['"];/,
'assert setting esmExternals: true emits namespace imports for external dependencies, creating an augmented namespace that exposes both named exports and default export'
);
const tmpEsm = path.join(projectRoot, '.tmp-contract-esm.mjs');
tmpFiles.push(tmpEsm);
fs.writeFileSync(tmpEsm, esmCode);
const modEsm = (await import(`file://${tmpEsm.replace(/\\/g, '/')}`)).default;
assert.equal(
typeof modEsm.ext.helper,
'function',
'Named exports are accessible from augmented namespace when esmExternals is true'
);
assert.equal(modEsm.ext.helper(), 'helped');
assert.equal(modEsm.ext.version, '1.0.0');
assert.deepEqual(modEsm.ext.default, { defaultKey: 'defaultValue' });
// -------------------------------------------------------------------------
// Contract Assertion 3:
// esmExternals accepts an array of package IDs to selectively emit namespace
// imports for specified ESM dependencies while leaving other externals as default imports.
// -------------------------------------------------------------------------
const selectiveBundle = await rollup({
input: 'entry-cjs.cjs',
external: ['mock-external-esm', 'mock-other-pkg'],
plugins: [virtualEntry, commonjs({ esmExternals: ['mock-external-esm'] })]
});
const { output: selectiveOutput } = await selectiveBundle.generate({ format: 'es' });
const selectiveCode = selectiveOutput[0].code;
assert.match(
selectiveCode,
/import\s+\*\s+as\s+mockExternalEsm\s+from\s+['"]mock-external-esm['"];/,
'assert esmExternals accepts an array of package IDs to selectively emit namespace imports for specified ESM dependencies while leaving other externals as default imports'
);
assert.match(
selectiveCode,
/import\s+require\$\$\d+\s+from\s+['"]mock-other-pkg['"];/,
'Non-targeted external module remains a default import'
);
// -------------------------------------------------------------------------
// Contract Assertion 4:
// esmExternals accepts a predicate function to dynamically determine which
// external dependencies are imported as ES module namespaces.
// -------------------------------------------------------------------------
const fnBundle = await rollup({
input: 'entry-cjs.cjs',
external: ['mock-external-esm', 'mock-other-pkg'],
plugins: [
virtualEntry,
commonjs({
esmExternals: (id) => id.includes('external-esm')
})
]
});
const { output: fnOutput } = await fnBundle.generate({ format: 'es' });
const fnCode = fnOutput[0].code;
assert.match(
fnCode,
/import\s+\*\s+as\s+mockExternalEsm\s+from\s+['"]mock-external-esm['"];/,
'assert esmExternals accepts a predicate function to dynamically determine which external dependencies are imported as ES module namespaces'
);
assert.match(
fnCode,
/import\s+require\$\$\d+\s+from\s+['"]mock-other-pkg['"];/,
'Predicate returning false renders default import'
);
console.log('All contract assertions passed successfully.');
} finally {
for (const f of tmpFiles) {
if (fs.existsSync(f)) {
fs.unlinkSync(f);
}
}
if (fs.existsSync(mockModuleDir)) {
fs.rmSync(mockModuleDir, { recursive: true, force: true });
}
if (fs.existsSync(mockOtherDir)) {
fs.rmSync(mockOtherDir, { recursive: true, force: true });
}
}
}
runContract().catch((err) => {
console.error('Contract failed:', err);
process.exit(1);
});
原始种子者
匿名