fix(resolve): fix resolve cache to consider conditions and more (#18302)

This commit is contained in:
Hiroshi Ogawa 2024-10-10 16:48:36 +09:00 committed by GitHub
parent af3cddf40c
commit 2017a330f5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 284 additions and 31 deletions

View File

@ -0,0 +1,209 @@
import path from 'node:path'
import { describe, expect, onTestFinished, test } from 'vitest'
import type { RollupOutput } from 'rollup'
import { createServer } from '../server'
import { defineConfig } from '../config'
import { createBuilder } from '../build'
import { createServerModuleRunner } from '../ssr/runtime/serverModuleRunner'
describe('custom environment conditions', () => {
function getConfig() {
return defineConfig({
root: import.meta.dirname,
logLevel: 'error',
server: {
middlewareMode: true,
},
environments: {
// no web / default
ssr: {
resolve: {
noExternal: true,
},
build: {
outDir: path.join(
import.meta.dirname,
'fixtures/test-dep-conditions/dist/ssr',
),
rollupOptions: {
input: { index: '@vitejs/test-dep-conditions' },
},
},
},
// web / worker
worker: {
webCompatible: true,
resolve: {
noExternal: true,
conditions: ['worker'],
},
build: {
outDir: path.join(
import.meta.dirname,
'fixtures/test-dep-conditions/dist/worker',
),
rollupOptions: {
input: { index: '@vitejs/test-dep-conditions' },
},
},
},
// web / custom1
custom1: {
webCompatible: true,
resolve: {
noExternal: true,
conditions: ['custom1'],
},
build: {
outDir: path.join(
import.meta.dirname,
'fixtures/test-dep-conditions/dist/custom1',
),
rollupOptions: {
input: { index: '@vitejs/test-dep-conditions' },
},
},
},
// no web / custom2
custom2: {
webCompatible: false,
resolve: {
noExternal: true,
conditions: ['custom2'],
},
build: {
outDir: path.join(
import.meta.dirname,
'fixtures/test-dep-conditions/dist/custom2',
),
rollupOptions: {
input: { index: '@vitejs/test-dep-conditions' },
},
},
},
// no web / custom3
custom3: {
webCompatible: false,
resolve: {
noExternal: true,
conditions: ['custom3'],
},
build: {
outDir: path.join(
import.meta.dirname,
'fixtures/test-dep-conditions/dist/custom3',
),
rollupOptions: {
input: { index: '@vitejs/test-dep-conditions' },
},
},
},
// same as custom3
custom3_2: {
webCompatible: false,
resolve: {
noExternal: true,
conditions: ['custom3'],
},
build: {
outDir: path.join(
import.meta.dirname,
'fixtures/test-dep-conditions/dist/custom3_2',
),
rollupOptions: {
input: { index: '@vitejs/test-dep-conditions' },
},
},
},
},
})
}
test('dev', async () => {
const server = await createServer(getConfig())
onTestFinished(() => server.close())
const results: Record<string, unknown> = {}
for (const key of [
'ssr',
'worker',
'custom1',
'custom2',
'custom3',
'custom3_2',
]) {
const runner = createServerModuleRunner(server.environments[key], {
hmr: {
logger: false,
},
sourcemapInterceptor: false,
})
const mod = await runner.import('@vitejs/test-dep-conditions')
results[key] = mod.default
}
expect(results).toMatchInlineSnapshot(`
{
"custom1": "index.custom1.js",
"custom2": "index.custom2.js",
"custom3": "index.custom3.js",
"custom3_2": "index.custom3.js",
"ssr": "index.default.js",
"worker": "index.worker.js",
}
`)
})
test('css', async () => {
const server = await createServer(getConfig())
onTestFinished(() => server.close())
const modJs = await server.ssrLoadModule(
'/fixtures/test-dep-conditions-app/entry.js',
)
const modCss = await server.ssrLoadModule(
'/fixtures/test-dep-conditions-app/entry.css?inline',
)
expect([modCss.default.replace(/\s+/g, ' '), modJs.default])
.toMatchInlineSnapshot(`
[
".test-css { color: orange; } ",
"index.default.js",
]
`)
})
test('build', async () => {
const builder = await createBuilder(getConfig())
const results: Record<string, unknown> = {}
for (const key of [
'ssr',
'worker',
'custom1',
'custom2',
'custom3',
'custom3_2',
]) {
const output = await builder.build(builder.environments[key])
const chunk = (output as RollupOutput).output[0]
const mod = await import(
path.join(
import.meta.dirname,
'fixtures/test-dep-conditions/dist',
key,
chunk.fileName,
)
)
results[key] = mod.default
}
expect(results).toMatchInlineSnapshot(`
{
"custom1": "index.custom1.js",
"custom2": "index.custom2.js",
"custom3": "index.custom3.js",
"custom3_2": "index.custom3.js",
"ssr": "index.default.js",
"worker": "index.worker.js",
}
`)
})
})

View File

@ -0,0 +1 @@
@import '@vitejs/test-dep-conditions';

View File

@ -0,0 +1,2 @@
import dep from '@vitejs/test-dep-conditions'
export default dep

View File

@ -0,0 +1 @@
export default 'index.browser.js'

View File

@ -0,0 +1,3 @@
.test-css {
color: orange;
}

View File

@ -0,0 +1 @@
export default 'index.custom1.js'

View File

@ -0,0 +1 @@
export default 'index.custom2.js'

View File

@ -0,0 +1 @@
export default 'index.custom3.js'

View File

@ -0,0 +1 @@
export default 'index.default.js'

View File

@ -0,0 +1 @@
export default 'index.worker.js'

View File

@ -0,0 +1,16 @@
{
"name": "@vitejs/test-dep-conditions",
"private": true,
"type": "module",
"exports": {
".": {
"style": "./index.css",
"custom1": "./index.custom1.js",
"custom2": "./index.custom2.js",
"custom3": "./index.custom3.js",
"worker": "./index.worker.js",
"browser": "./index.browser.js",
"default": "./index.default.js"
}
}
}

View File

@ -3,6 +3,7 @@
"private": true,
"version": "0.0.0",
"dependencies": {
"@vitejs/cjs-ssr-dep": "link:./fixtures/cjs-ssr-dep"
"@vitejs/cjs-ssr-dep": "link:./fixtures/cjs-ssr-dep",
"@vitejs/test-dep-conditions": "file:./fixtures/test-dep-conditions"
}
}

View File

@ -9,6 +9,7 @@ import {
tryStatSync,
} from './utils'
import type { Plugin } from './plugin'
import type { InternalResolveOptions } from './plugins/resolve'
let pnp: typeof import('pnpapi') | undefined
if (process.versions.pnp) {
@ -23,10 +24,15 @@ export type PackageCache = Map<string, PackageData>
export interface PackageData {
dir: string
hasSideEffects: (id: string) => boolean | 'no-treeshake' | null
webResolvedImports: Record<string, string | undefined>
nodeResolvedImports: Record<string, string | undefined>
setResolvedCache: (key: string, entry: string, targetWeb: boolean) => void
getResolvedCache: (key: string, targetWeb: boolean) => string | undefined
setResolvedCache: (
key: string,
entry: string,
options: InternalResolveOptions,
) => void
getResolvedCache: (
key: string,
options: InternalResolveOptions,
) => string | undefined
data: {
[field: string]: any
name: string
@ -201,31 +207,35 @@ export function loadPackageData(pkgPath: string): PackageData {
hasSideEffects = () => null
}
const resolvedCache: Record<string, string | undefined> = {}
const pkg: PackageData = {
dir: pkgDir,
data,
hasSideEffects,
webResolvedImports: {},
nodeResolvedImports: {},
setResolvedCache(key: string, entry: string, targetWeb: boolean) {
if (targetWeb) {
pkg.webResolvedImports[key] = entry
} else {
pkg.nodeResolvedImports[key] = entry
}
setResolvedCache(key, entry, options) {
resolvedCache[getResolveCacheKey(key, options)] = entry
},
getResolvedCache(key: string, targetWeb: boolean) {
if (targetWeb) {
return pkg.webResolvedImports[key]
} else {
return pkg.nodeResolvedImports[key]
}
getResolvedCache(key, options) {
return resolvedCache[getResolveCacheKey(key, options)]
},
}
return pkg
}
function getResolveCacheKey(key: string, options: InternalResolveOptions) {
// cache key needs to include options which affect
// `resolvePackageEntry` or `resolveDeepImport`
return [
key,
options.webCompatible ? '1' : '0',
options.isRequire ? '1' : '0',
options.conditions.join('_'),
options.extensions.join('_'),
options.mainFields.join('_'),
].join('|')
}
export function watchPackageDataPlugin(packageCache: PackageCache): Plugin {
// a list of files to watch before the plugin is ready
const watchQueue = new Set<string>()

View File

@ -1022,7 +1022,7 @@ export function resolvePackageEntry(
): string | undefined {
const { file: idWithoutPostfix, postfix } = splitFileAndPostfix(id)
const cached = getResolvedCache('.', !!options.webCompatible)
const cached = getResolvedCache('.', options)
if (cached) {
return cached + postfix
}
@ -1094,7 +1094,7 @@ export function resolvePackageEntry(
resolvedEntryPoint,
)}${postfix !== '' ? ` (postfix: ${postfix})` : ''}`,
)
setResolvedCache('.', resolvedEntryPoint, !!options.webCompatible)
setResolvedCache('.', resolvedEntryPoint, options)
return resolvedEntryPoint + postfix
}
}
@ -1151,16 +1151,10 @@ function resolveExportsOrImports(
function resolveDeepImport(
id: string,
{
webResolvedImports,
setResolvedCache,
getResolvedCache,
dir,
data,
}: PackageData,
{ setResolvedCache, getResolvedCache, dir, data }: PackageData,
options: InternalResolveOptions,
): string | undefined {
const cache = getResolvedCache(id, !!options.webCompatible)
const cache = getResolvedCache(id, options)
if (cache) {
return cache
}
@ -1200,7 +1194,8 @@ function resolveDeepImport(
if (mapped) {
relativeId = mapped + postfix
} else if (mapped === false) {
return (webResolvedImports[id] = browserExternalId)
setResolvedCache(id, browserExternalId, options)
return browserExternalId
}
}
@ -1214,7 +1209,7 @@ function resolveDeepImport(
debug?.(
`[node/deep-import] ${colors.cyan(id)} -> ${colors.dim(resolved)}`,
)
setResolvedCache(id, resolved, !!options.webCompatible)
setResolvedCache(id, resolved, options)
return resolved
}
}

View File

@ -427,9 +427,14 @@ importers:
'@vitejs/cjs-ssr-dep':
specifier: link:./fixtures/cjs-ssr-dep
version: link:fixtures/cjs-ssr-dep
'@vitejs/test-dep-conditions':
specifier: file:./fixtures/test-dep-conditions
version: file:packages/vite/src/node/__tests__/fixtures/test-dep-conditions
packages/vite/src/node/__tests__/fixtures/cjs-ssr-dep: {}
packages/vite/src/node/__tests__/fixtures/test-dep-conditions: {}
packages/vite/src/node/__tests__/packages/module: {}
packages/vite/src/node/__tests__/packages/name: {}
@ -3602,6 +3607,9 @@ 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-conditions@file:packages/vite/src/node/__tests__/fixtures/test-dep-conditions':
resolution: {directory: packages/vite/src/node/__tests__/fixtures/test-dep-conditions, type: directory}
'@vitejs/test-dep-css-require@file:playground/optimize-deps/dep-css-require':
resolution: {directory: playground/optimize-deps/dep-css-require, type: directory}
@ -9215,6 +9223,8 @@ snapshots:
'@vitejs/test-dep-cjs-with-assets@file:playground/optimize-deps/dep-cjs-with-assets': {}
'@vitejs/test-dep-conditions@file:packages/vite/src/node/__tests__/fixtures/test-dep-conditions': {}
'@vitejs/test-dep-css-require@file:playground/optimize-deps/dep-css-require': {}
'@vitejs/test-dep-esbuild-plugin-transform@file:playground/optimize-deps/dep-esbuild-plugin-transform': {}