diff --git a/packages/vite/src/node/optimizer/esbuildDepPlugin.ts b/packages/vite/src/node/optimizer/esbuildDepPlugin.ts
index 270c810d39ffd6..c934bf538b4703 100644
--- a/packages/vite/src/node/optimizer/esbuildDepPlugin.ts
+++ b/packages/vite/src/node/optimizer/esbuildDepPlugin.ts
@@ -8,6 +8,7 @@ import {
isBuiltin,
isCSSRequest,
isExternalUrl,
+ isNodeBuiltin,
moduleListContains,
normalizePath,
} from '../utils'
@@ -337,10 +338,10 @@ export function esbuildCjsExternalPlugin(
build.onLoad(
{ filter: /.*/, namespace: cjsExternalFacadeNamespace },
(args) => ({
- contents:
- `import * as m from ${JSON.stringify(
- nonFacadePrefix + args.path,
- )};` + `module.exports = { ...m };`,
+ contents: `\
+import * as m from ${JSON.stringify(nonFacadePrefix + args.path)};
+module.exports = ${isNodeBuiltin(args.path) ? 'm.default' : '{ ...m }'};
+`,
}),
)
},
diff --git a/playground/optimize-deps/__tests__/optimize-deps.spec.ts b/playground/optimize-deps/__tests__/optimize-deps.spec.ts
index f9f34d50bcbb45..65260405969c8c 100644
--- a/playground/optimize-deps/__tests__/optimize-deps.spec.ts
+++ b/playground/optimize-deps/__tests__/optimize-deps.spec.ts
@@ -365,8 +365,11 @@ test('external package name with asset extension', async () => {
).toBe(String(isServe))
})
-test('dependency with external sub-dependency', async () => {
+test('dependency with external sub-dependencies', async () => {
await expectWithRetry(() =>
- page.textContent('.dep-cjs-with-external-dep'),
+ page.textContent('.dep-cjs-with-external-deps-object'),
).toBe('ok')
+ await expectWithRetry(() =>
+ page.textContent('.dep-cjs-with-external-deps-node-builtin'),
+ ).toBe('foo bar')
})
diff --git a/playground/optimize-deps/dep-cjs-with-external-dep/index.js b/playground/optimize-deps/dep-cjs-with-external-dep/index.js
deleted file mode 100644
index 18b7d613194bae..00000000000000
--- a/playground/optimize-deps/dep-cjs-with-external-dep/index.js
+++ /dev/null
@@ -1,4 +0,0 @@
-const external = require('@vitejs/test-dep-esm-external')
-// eslint-disable-next-line no-prototype-builtins
-const result = external.hasOwnProperty('foo') ? 'ok' : 'error'
-module.exports = { result }
diff --git a/playground/optimize-deps/dep-cjs-with-external-dep/package.json b/playground/optimize-deps/dep-cjs-with-external-dep/package.json
deleted file mode 100644
index 39e8bf01d732d0..00000000000000
--- a/playground/optimize-deps/dep-cjs-with-external-dep/package.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "name": "@vitejs/test-dep-cjs-with-external-dep",
- "private": true,
- "version": "0.0.0",
- "main": "index.js",
- "dependencies": {
- "@vitejs/test-dep-esm-external": "file:../dep-esm-external"
- }
-}
diff --git a/playground/optimize-deps/dep-cjs-with-external-deps/index.js b/playground/optimize-deps/dep-cjs-with-external-deps/index.js
new file mode 100644
index 00000000000000..93fe8c56557cf3
--- /dev/null
+++ b/playground/optimize-deps/dep-cjs-with-external-deps/index.js
@@ -0,0 +1,8 @@
+// `stream` is used as the package name for `@vitejs/test-dep-esm-dummy-node-builtin` so that it is treated like a Node builtin
+// eslint-disable-next-line import-x/no-nodejs-modules
+const externalDummyNodeBuiltin = require('stream')
+const external = require('@vitejs/test-dep-esm-external')
+// eslint-disable-next-line no-prototype-builtins
+const externalResult = external.hasOwnProperty('foo') ? 'ok' : 'error'
+const externalDummyNodeBuiltinResult = `${externalDummyNodeBuiltin()} ${externalDummyNodeBuiltin.bar}`
+module.exports = { externalResult, externalDummyNodeBuiltinResult }
diff --git a/playground/optimize-deps/dep-cjs-with-external-deps/package.json b/playground/optimize-deps/dep-cjs-with-external-deps/package.json
new file mode 100644
index 00000000000000..877db9d13be18e
--- /dev/null
+++ b/playground/optimize-deps/dep-cjs-with-external-deps/package.json
@@ -0,0 +1,10 @@
+{
+ "name": "@vitejs/test-dep-cjs-with-external-deps",
+ "private": true,
+ "version": "0.0.0",
+ "main": "index.js",
+ "dependencies": {
+ "@vitejs/test-dep-esm-external": "file:../dep-esm-external",
+ "stream": "file:../dep-esm-dummy-node-builtin"
+ }
+}
diff --git a/playground/optimize-deps/dep-esm-dummy-node-builtin/index.js b/playground/optimize-deps/dep-esm-dummy-node-builtin/index.js
new file mode 100644
index 00000000000000..b48be1f1a732a7
--- /dev/null
+++ b/playground/optimize-deps/dep-esm-dummy-node-builtin/index.js
@@ -0,0 +1,9 @@
+function foo() {
+ return 'foo'
+}
+
+foo.bar = 'bar'
+
+export const bar = 'bar'
+
+export default foo
diff --git a/playground/optimize-deps/dep-esm-dummy-node-builtin/package.json b/playground/optimize-deps/dep-esm-dummy-node-builtin/package.json
new file mode 100644
index 00000000000000..42403c772cd08b
--- /dev/null
+++ b/playground/optimize-deps/dep-esm-dummy-node-builtin/package.json
@@ -0,0 +1,7 @@
+{
+ "name": "@vitejs/test-dep-esm-dummy-node-builtin",
+ "private": true,
+ "version": "0.0.0",
+ "main": "index.js",
+ "type": "module"
+}
diff --git a/playground/optimize-deps/index.html b/playground/optimize-deps/index.html
index c3493cc412baec..da0bf2ce834f2e 100644
--- a/playground/optimize-deps/index.html
+++ b/playground/optimize-deps/index.html
@@ -310,12 +310,22 @@
Pre-bundle transitive dependency 'some-package.pdf'
import * as all from '@vitejs/test-dep-source-map-no-sources/all.js'
-Pre-bundle dependency with external sub-dependency
+Pre-bundle dependency with external sub-dependencies
- require('some-external-sub-dependency') returns a plain object:
- ???
+ require('some-external-sub-dependency') returns a plain object rather than a
+ module namespace object:
+ ???
+
+
+ require('some-external-sub-dependency') returns the default export if the
+ dependency is a Node builtin:
+ ???
diff --git a/playground/optimize-deps/package.json b/playground/optimize-deps/package.json
index 5ebad36a3bfc65..23868a4e9e8471 100644
--- a/playground/optimize-deps/package.json
+++ b/playground/optimize-deps/package.json
@@ -18,7 +18,7 @@
"@vitejs/test-dep-cjs-compiled-from-cjs": "file:./dep-cjs-compiled-from-cjs",
"@vitejs/test-dep-cjs-compiled-from-esm": "file:./dep-cjs-compiled-from-esm",
"@vitejs/test-dep-cjs-with-assets": "file:./dep-cjs-with-assets",
- "@vitejs/test-dep-cjs-with-external-dep": "file:./dep-cjs-with-external-dep",
+ "@vitejs/test-dep-cjs-with-external-deps": "file:./dep-cjs-with-external-deps",
"@vitejs/test-dep-css-require": "file:./dep-css-require",
"@vitejs/test-dep-esbuild-plugin-transform": "file:./dep-esbuild-plugin-transform",
"@vitejs/test-dep-incompatible": "file:./dep-incompatible",
diff --git a/playground/optimize-deps/vite.config.js b/playground/optimize-deps/vite.config.js
index 4e6f1c7fc16ecc..adcea2df9bc3f2 100644
--- a/playground/optimize-deps/vite.config.js
+++ b/playground/optimize-deps/vite.config.js
@@ -23,12 +23,13 @@ export default defineConfig({
'@vitejs/test-dep-optimize-exports-with-glob/**/*',
'@vitejs/test-dep-optimize-exports-with-root-glob/**/*.js',
'@vitejs/test-dep-optimize-with-glob/**/*.js',
- '@vitejs/test-dep-cjs-with-external-dep',
+ '@vitejs/test-dep-cjs-with-external-deps',
],
exclude: [
'@vitejs/test-nested-exclude',
'@vitejs/test-dep-non-optimized',
'@vitejs/test-dep-esm-external',
+ 'stream',
],
esbuildOptions: {
plugins: [
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 192b00269fffed..3bd53a49c50361 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -959,9 +959,9 @@ importers:
'@vitejs/test-dep-cjs-with-assets':
specifier: file:./dep-cjs-with-assets
version: file:playground/optimize-deps/dep-cjs-with-assets
- '@vitejs/test-dep-cjs-with-external-dep':
- specifier: file:./dep-cjs-with-external-dep
- version: file:playground/optimize-deps/dep-cjs-with-external-dep
+ '@vitejs/test-dep-cjs-with-external-deps':
+ specifier: file:./dep-cjs-with-external-deps
+ version: file:playground/optimize-deps/dep-cjs-with-external-deps
'@vitejs/test-dep-css-require':
specifier: file:./dep-css-require
version: file:playground/optimize-deps/dep-css-require
@@ -1094,16 +1094,21 @@ importers:
playground/optimize-deps/dep-cjs-with-assets: {}
- playground/optimize-deps/dep-cjs-with-external-dep:
+ playground/optimize-deps/dep-cjs-with-external-deps:
dependencies:
'@vitejs/test-dep-esm-external':
specifier: file:../dep-esm-external
version: file:playground/optimize-deps/dep-esm-external
+ stream:
+ specifier: file:../dep-esm-dummy-node-builtin
+ version: '@vitejs/test-dep-esm-dummy-node-builtin@file:playground/optimize-deps/dep-esm-dummy-node-builtin'
playground/optimize-deps/dep-css-require: {}
playground/optimize-deps/dep-esbuild-plugin-transform: {}
+ playground/optimize-deps/dep-esm-dummy-node-builtin: {}
+
playground/optimize-deps/dep-esm-external: {}
playground/optimize-deps/dep-incompatible: {}
@@ -3654,8 +3659,8 @@ packages:
'@vitejs/test-dep-cjs-with-assets@file:playground/optimize-deps/dep-cjs-with-assets':
resolution: {directory: playground/optimize-deps/dep-cjs-with-assets, type: directory}
- '@vitejs/test-dep-cjs-with-external-dep@file:playground/optimize-deps/dep-cjs-with-external-dep':
- resolution: {directory: playground/optimize-deps/dep-cjs-with-external-dep, type: directory}
+ '@vitejs/test-dep-cjs-with-external-deps@file:playground/optimize-deps/dep-cjs-with-external-deps':
+ resolution: {directory: playground/optimize-deps/dep-cjs-with-external-deps, type: directory}
'@vitejs/test-dep-conditions@file:packages/vite/src/node/__tests__/fixtures/test-dep-conditions':
resolution: {directory: packages/vite/src/node/__tests__/fixtures/test-dep-conditions, type: directory}
@@ -3666,6 +3671,9 @@ packages:
'@vitejs/test-dep-esbuild-plugin-transform@file:playground/optimize-deps/dep-esbuild-plugin-transform':
resolution: {directory: playground/optimize-deps/dep-esbuild-plugin-transform, type: directory}
+ '@vitejs/test-dep-esm-dummy-node-builtin@file:playground/optimize-deps/dep-esm-dummy-node-builtin':
+ resolution: {directory: playground/optimize-deps/dep-esm-dummy-node-builtin, type: directory}
+
'@vitejs/test-dep-esm-external@file:playground/optimize-deps/dep-esm-external':
resolution: {directory: playground/optimize-deps/dep-esm-external, type: directory}
@@ -9289,9 +9297,10 @@ snapshots:
'@vitejs/test-dep-cjs-with-assets@file:playground/optimize-deps/dep-cjs-with-assets': {}
- '@vitejs/test-dep-cjs-with-external-dep@file:playground/optimize-deps/dep-cjs-with-external-dep':
+ '@vitejs/test-dep-cjs-with-external-deps@file:playground/optimize-deps/dep-cjs-with-external-deps':
dependencies:
'@vitejs/test-dep-esm-external': file:playground/optimize-deps/dep-esm-external
+ stream: '@vitejs/test-dep-esm-dummy-node-builtin@file:playground/optimize-deps/dep-esm-dummy-node-builtin'
'@vitejs/test-dep-conditions@file:packages/vite/src/node/__tests__/fixtures/test-dep-conditions': {}
@@ -9299,6 +9308,8 @@ snapshots:
'@vitejs/test-dep-esbuild-plugin-transform@file:playground/optimize-deps/dep-esbuild-plugin-transform': {}
+ '@vitejs/test-dep-esm-dummy-node-builtin@file:playground/optimize-deps/dep-esm-dummy-node-builtin': {}
+
'@vitejs/test-dep-esm-external@file:playground/optimize-deps/dep-esm-external': {}
'@vitejs/test-dep-including-a@file:playground/preload/dep-including-a':