fix: preserve default export from externalized packages (fixes #10258) (#10406)

fixes https://github.com/vitejs/vite/issues/10258
This commit is contained in:
翠 / green 2022-11-24 22:47:18 +09:00 committed by GitHub
parent d6b4ee58d6
commit 88b001bc08
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 119 additions and 55 deletions

View File

@ -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) => ({
path: args.path,
namespace: 'external'
}))
build.onResolve({ filter }, (args) => {
if (args.kind === 'require-call') {
return {
path: args.path,
namespace: cjsExternalFacadeNamespace
}
}
build.onLoad({ filter: /.*/, namespace: 'external' }, (args) => ({
contents: `export * from ${JSON.stringify(args.path)}`
}))
return {
path: args.path,
external: true
}
})
build.onLoad(
{ filter: /.*/, namespace: cjsExternalFacadeNamespace },
(args) => ({
contents:
`import * as m from ${JSON.stringify(
nonFacadePrefix + args.path
)};` + `module.exports = m;`
})
)
}
}
}

View File

@ -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

View File

@ -1,3 +0,0 @@
import { version } from 'vue'
document.querySelector('#imported-vue-version').textContent = version

View File

@ -1,8 +0,0 @@
{
"name": "@vitejs/dep-that-imports-vue",
"private": true,
"version": "0.0.0",
"dependencies": {
"vue": "^3.2.45"
}
}

View File

@ -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')

View File

@ -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"
}
}

View File

@ -1,3 +0,0 @@
const { version } = require('vue')
document.querySelector('#required-vue-version').textContent = version

View File

@ -1,8 +0,0 @@
{
"name": "@vitejs/dep-that-requires-vue",
"private": true,
"version": "0.0.0",
"dependencies": {
"vue": "^3.2.45"
}
}

View File

@ -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')

View File

@ -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"
}
}

View File

@ -7,7 +7,9 @@
<script type="importmap">
{
"imports": {
"vue": "https://unpkg.com/vue@3.2.0/dist/vue.runtime.esm-browser.js"
"vue": "https://unpkg.com/vue@3.2.0/dist/vue.runtime.esm-browser.js",
"slash5": "https://unpkg.com/slash@5.0.0/index.js",
"slash3": "https://esm.sh/slash@3.0.0"
}
}
</script>
@ -15,6 +17,9 @@
<body>
<p>Imported Vue version: <span id="imported-vue-version"></span></p>
<p>Required Vue version: <span id="required-vue-version"></span></p>
<p>Imported slash5 exists: <span id="imported-slash5-exists"></span></p>
<p>Imported slash3 exists: <span id="imported-slash3-exists"></span></p>
<p>Required slash3 exists: <span id="required-slash3-exists"></span></p>
<script type="module" src="/src/main.js"></script>
</body>
</html>

View File

@ -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"
}

View File

@ -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'

View File

@ -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']
}
}
})

View File

@ -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