diff --git a/packages/vite/src/node/optimizer/esbuildDepPlugin.ts b/packages/vite/src/node/optimizer/esbuildDepPlugin.ts index 3370cec68a6383..2def9336e8a3d6 100644 --- a/packages/vite/src/node/optimizer/esbuildDepPlugin.ts +++ b/packages/vite/src/node/optimizer/esbuildDepPlugin.ts @@ -16,6 +16,9 @@ const externalWithConversionNamespace = 'vite:dep-pre-bundle:external-conversion' const convertedExternalPrefix = 'vite-dep-pre-bundle-external:' +const cjsExternalFacadeNamespace = 'vite:cjs-external-facade' +const nonFacadePrefix = 'vite-cjs-external-facade:' + const externalTypes = [ 'css', // supported pre-processor types @@ -268,19 +271,36 @@ export function esbuildCjsExternalPlugin(externals: string[]): Plugin { `^${text.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')}$` const filter = new RegExp(externals.map(escape).join('|')) - build.onResolve({ filter: /.*/, namespace: 'external' }, (args) => ({ - path: args.path, - external: true - })) + build.onResolve({ filter: new RegExp(`^${nonFacadePrefix}`) }, (args) => { + return { + path: args.path.slice(nonFacadePrefix.length), + external: true + } + }) + + build.onResolve({ filter }, (args) => { + if (args.kind === 'require-call') { + return { + path: args.path, + namespace: cjsExternalFacadeNamespace + } + } - build.onResolve({ filter }, (args) => ({ - path: args.path, - namespace: 'external' - })) + return { + path: args.path, + external: true + } + }) - build.onLoad({ filter: /.*/, namespace: 'external' }, (args) => ({ - contents: `export * from ${JSON.stringify(args.path)}` - })) + build.onLoad( + { filter: /.*/, namespace: cjsExternalFacadeNamespace }, + (args) => ({ + contents: + `import * as m from ${JSON.stringify( + nonFacadePrefix + args.path + )};` + `module.exports = m;` + }) + ) } } } diff --git a/playground/external/__tests__/external.spec.ts b/playground/external/__tests__/external.spec.ts index 029ffc8422a3ba..7504b6ae1c293c 100644 --- a/playground/external/__tests__/external.spec.ts +++ b/playground/external/__tests__/external.spec.ts @@ -7,6 +7,12 @@ test('importmap', () => { ) }) +test('should have default exports', async () => { + expect(await page.textContent('#imported-slash5-exists')).toBe('true') + expect(await page.textContent('#imported-slash3-exists')).toBe('true') + expect(await page.textContent('#required-slash3-exists')).toBe('true') +}) + describe.runIf(isBuild)('build', () => { test('should externalize imported packages', async () => { // If `vue` is successfully externalized, the page should use the version from the import map diff --git a/playground/external/dep-that-imports-vue/index.js b/playground/external/dep-that-imports-vue/index.js deleted file mode 100644 index aa79957e9b3b49..00000000000000 --- a/playground/external/dep-that-imports-vue/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import { version } from 'vue' - -document.querySelector('#imported-vue-version').textContent = version diff --git a/playground/external/dep-that-imports-vue/package.json b/playground/external/dep-that-imports-vue/package.json deleted file mode 100644 index 3a57f33cdf5eda..00000000000000 --- a/playground/external/dep-that-imports-vue/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "@vitejs/dep-that-imports-vue", - "private": true, - "version": "0.0.0", - "dependencies": { - "vue": "^3.2.45" - } -} diff --git a/playground/external/dep-that-imports/index.js b/playground/external/dep-that-imports/index.js new file mode 100644 index 00000000000000..096ea934cc4965 --- /dev/null +++ b/playground/external/dep-that-imports/index.js @@ -0,0 +1,9 @@ +import { version } from 'vue' +import slash5 from 'slash5' +import slash3 from 'slash3' + +document.querySelector('#imported-vue-version').textContent = version +document.querySelector('#imported-slash5-exists').textContent = + !!slash5('foo/bar') +document.querySelector('#imported-slash3-exists').textContent = + !!slash3('foo/bar') diff --git a/playground/external/dep-that-imports/package.json b/playground/external/dep-that-imports/package.json new file mode 100644 index 00000000000000..b688165c9fc521 --- /dev/null +++ b/playground/external/dep-that-imports/package.json @@ -0,0 +1,10 @@ +{ + "name": "@vitejs/dep-that-imports", + "private": true, + "version": "0.0.0", + "dependencies": { + "slash3": "npm:slash@^3.0.0", + "slash5": "npm:slash@^5.0.0", + "vue": "^3.2.45" + } +} diff --git a/playground/external/dep-that-requires-vue/index.js b/playground/external/dep-that-requires-vue/index.js deleted file mode 100644 index 0b573021a00b57..00000000000000 --- a/playground/external/dep-that-requires-vue/index.js +++ /dev/null @@ -1,3 +0,0 @@ -const { version } = require('vue') - -document.querySelector('#required-vue-version').textContent = version diff --git a/playground/external/dep-that-requires-vue/package.json b/playground/external/dep-that-requires-vue/package.json deleted file mode 100644 index b96a6e4f360abd..00000000000000 --- a/playground/external/dep-that-requires-vue/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "@vitejs/dep-that-requires-vue", - "private": true, - "version": "0.0.0", - "dependencies": { - "vue": "^3.2.45" - } -} diff --git a/playground/external/dep-that-requires/index.js b/playground/external/dep-that-requires/index.js new file mode 100644 index 00000000000000..6f0dd6124d829d --- /dev/null +++ b/playground/external/dep-that-requires/index.js @@ -0,0 +1,7 @@ +const { version } = require('vue') +// require('slash5') // cannot require ESM +const slash3 = require('slash3') + +document.querySelector('#required-vue-version').textContent = version +document.querySelector('#required-slash3-exists').textContent = + !!slash3('foo/bar') diff --git a/playground/external/dep-that-requires/package.json b/playground/external/dep-that-requires/package.json new file mode 100644 index 00000000000000..bc1195ccfc6add --- /dev/null +++ b/playground/external/dep-that-requires/package.json @@ -0,0 +1,10 @@ +{ + "name": "@vitejs/dep-that-requires", + "private": true, + "version": "0.0.0", + "dependencies": { + "slash3": "npm:slash@^3.0.0", + "slash5": "npm:slash@^5.0.0", + "vue": "^3.2.45" + } +} diff --git a/playground/external/index.html b/playground/external/index.html index 66a16c329c1fc5..e07492875bdc1d 100644 --- a/playground/external/index.html +++ b/playground/external/index.html @@ -7,7 +7,9 @@ @@ -15,6 +17,9 @@

Imported Vue version:

Required Vue version:

+

Imported slash5 exists:

+

Imported slash3 exists:

+

Required slash3 exists:

diff --git a/playground/external/package.json b/playground/external/package.json index 0cdff004e174ac..19ad4f96430d17 100644 --- a/playground/external/package.json +++ b/playground/external/package.json @@ -9,10 +9,12 @@ "preview": "vite preview" }, "dependencies": { - "@vitejs/dep-that-imports-vue": "file:./dep-that-imports-vue", - "@vitejs/dep-that-requires-vue": "file:./dep-that-requires-vue" + "@vitejs/dep-that-imports": "file:./dep-that-imports", + "@vitejs/dep-that-requires": "file:./dep-that-requires" }, "devDependencies": { + "slash3": "npm:slash@^3.0.0", + "slash5": "npm:slash@^5.0.0", "vite": "workspace:*", "vue": "^3.2.45" } diff --git a/playground/external/src/main.js b/playground/external/src/main.js index 0e1d3bece640e9..f16b94b75706e5 100644 --- a/playground/external/src/main.js +++ b/playground/external/src/main.js @@ -1,2 +1,2 @@ -import '@vitejs/dep-that-imports-vue' -import '@vitejs/dep-that-requires-vue' +import '@vitejs/dep-that-imports' +import '@vitejs/dep-that-requires' diff --git a/playground/external/vite.config.js b/playground/external/vite.config.js index fde8e763f810e0..1e38f9f65a18b5 100644 --- a/playground/external/vite.config.js +++ b/playground/external/vite.config.js @@ -1,13 +1,17 @@ import { defineConfig } from 'vite' export default defineConfig({ + optimizeDeps: { + include: ['dep-that-imports', 'dep-that-requires'], + exclude: ['vue', 'slash5'] + }, build: { minify: false, rollupOptions: { - external: ['vue'] + external: ['vue', 'slash3', 'slash5'] }, commonjsOptions: { - esmExternals: ['vue'] + esmExternals: ['vue', 'slash5'] } } }) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3fb60bdb5f559a..37236d377d430b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -500,27 +500,39 @@ importers: playground/external: specifiers: - '@vitejs/dep-that-imports-vue': file:./dep-that-imports-vue - '@vitejs/dep-that-requires-vue': file:./dep-that-requires-vue + '@vitejs/dep-that-imports': file:./dep-that-imports + '@vitejs/dep-that-requires': file:./dep-that-requires + slash3: npm:slash@^3.0.0 + slash5: npm:slash@^5.0.0 vite: workspace:* vue: ^3.2.45 dependencies: - '@vitejs/dep-that-imports-vue': file:playground/external/dep-that-imports-vue - '@vitejs/dep-that-requires-vue': file:playground/external/dep-that-requires-vue + '@vitejs/dep-that-imports': file:playground/external/dep-that-imports + '@vitejs/dep-that-requires': file:playground/external/dep-that-requires devDependencies: + slash3: /slash/3.0.0 + slash5: /slash/5.0.0 vite: link:../../packages/vite vue: 3.2.45 - playground/external/dep-that-imports-vue: + playground/external/dep-that-imports: specifiers: + slash3: npm:slash@^3.0.0 + slash5: npm:slash@^5.0.0 vue: ^3.2.45 dependencies: + slash3: /slash/3.0.0 + slash5: /slash/5.0.0 vue: 3.2.45 - playground/external/dep-that-requires-vue: + playground/external/dep-that-requires: specifiers: + slash3: npm:slash@^3.0.0 + slash5: npm:slash@^5.0.0 vue: ^3.2.45 dependencies: + slash3: /slash/3.0.0 + slash5: /slash/5.0.0 vue: 3.2.45 playground/file-delete-restore: @@ -8075,17 +8087,14 @@ packages: /slash/3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} - dev: true /slash/4.0.0: resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} engines: {node: '>=12'} - dev: true /slash/5.0.0: resolution: {integrity: sha512-n6KkmvKS0623igEVj3FF0OZs1gYYJ0o0Hj939yc1fyxl2xt+xYpLnzJB6xBSqOfV9ZFLEWodBBN/heZJahuIJQ==} engines: {node: '>=14.16'} - dev: true /slice-ansi/3.0.0: resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==} @@ -9218,19 +9227,23 @@ packages: version: 1.0.0 dev: false - file:playground/external/dep-that-imports-vue: - resolution: {directory: playground/external/dep-that-imports-vue, type: directory} - name: '@vitejs/dep-that-imports-vue' + file:playground/external/dep-that-imports: + resolution: {directory: playground/external/dep-that-imports, type: directory} + name: '@vitejs/dep-that-imports' version: 0.0.0 dependencies: + slash3: /slash/3.0.0 + slash5: /slash/5.0.0 vue: 3.2.45 dev: false - file:playground/external/dep-that-requires-vue: - resolution: {directory: playground/external/dep-that-requires-vue, type: directory} - name: '@vitejs/dep-that-requires-vue' + file:playground/external/dep-that-requires: + resolution: {directory: playground/external/dep-that-requires, type: directory} + name: '@vitejs/dep-that-requires' version: 0.0.0 dependencies: + slash3: /slash/3.0.0 + slash5: /slash/5.0.0 vue: 3.2.45 dev: false