diff --git a/packages/vite/src/module-runner/importMetaResolver.ts b/packages/vite/src/module-runner/importMetaResolver.ts index 25ccd8f0b54975..05dbe3b8427f50 100644 --- a/packages/vite/src/module-runner/importMetaResolver.ts +++ b/packages/vite/src/module-runner/importMetaResolver.ts @@ -46,3 +46,16 @@ export async function createImportMetaResolver(): Promise< `${customizationHookNamespace}${JSON.stringify([specifier, importer])}`, ) } + +// NOTE: use computed string to avoid `define` replacing `import.meta.resolve` when bundled +export const importMetaResolveWithCustomHookString: string = /* js */ ` + + (() => { + const resolve = 'resolve' + return (specifier, importer) => + import.meta[resolve]( + \`${customizationHookNamespace}\${JSON.stringify([specifier, importer])}\`, + ) + })() + +` diff --git a/packages/vite/src/node/__tests__/config.spec.ts b/packages/vite/src/node/__tests__/config.spec.ts index fddf467e130fda..7d592956f82bc3 100644 --- a/packages/vite/src/node/__tests__/config.spec.ts +++ b/packages/vite/src/node/__tests__/config.spec.ts @@ -839,7 +839,7 @@ describe('loadConfigFromFile', () => { `) }) - test('import.meta.main is correctly set', async () => { + test('import.meta properties are supported', async () => { const { config } = (await loadConfigFromFile( {} as any, path.resolve(fixtures, './import-meta/vite.config.ts'), @@ -851,6 +851,7 @@ describe('loadConfigFromFile', () => { expect(c.url).toContain('file://') expect(c.dirname).toContain('import-meta') expect(c.filename).toContain('vite.config.ts') + expect(c.resolved).toBe(c.url) }) describe('loadConfigFromFile with configLoader: native', () => { diff --git a/packages/vite/src/node/__tests__/fixtures/config/import-meta/package.json b/packages/vite/src/node/__tests__/fixtures/config/import-meta/package.json new file mode 100644 index 00000000000000..3dbc1ca591c055 --- /dev/null +++ b/packages/vite/src/node/__tests__/fixtures/config/import-meta/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} diff --git a/packages/vite/src/node/__tests__/fixtures/config/import-meta/vite.config.ts b/packages/vite/src/node/__tests__/fixtures/config/import-meta/vite.config.ts index 910f527ce12026..60ef3da4e3e29f 100644 --- a/packages/vite/src/node/__tests__/fixtures/config/import-meta/vite.config.ts +++ b/packages/vite/src/node/__tests__/fixtures/config/import-meta/vite.config.ts @@ -3,4 +3,5 @@ export default { url: import.meta.url, dirname: import.meta.dirname, filename: import.meta.filename, + resolved: import.meta.resolve('../import-meta/vite.config.ts'), } diff --git a/packages/vite/src/node/config.ts b/packages/vite/src/node/config.ts index fca201bdee4bda..4c8a4392175224 100644 --- a/packages/vite/src/node/config.ts +++ b/packages/vite/src/node/config.ts @@ -13,6 +13,10 @@ import { build } from 'esbuild' import type { Alias, AliasOptions } from '#dep-types/alias' import type { AnymatchFn } from '../types/anymatch' import { withTrailingSlash } from '../shared/utils' +import { + createImportMetaResolver, + importMetaResolveWithCustomHookString, +} from '../module-runner/importMetaResolver' import { CLIENT_ENTRY, DEFAULT_ASSETS_RE, @@ -1925,10 +1929,14 @@ async function bundleConfigFile( fileName: string, isESM: boolean, ): Promise<{ code: string; dependencies: string[] }> { + let importMetaResolverRegistered = false + const root = path.dirname(fileName) const dirnameVarName = '__vite_injected_original_dirname' const filenameVarName = '__vite_injected_original_filename' const importMetaUrlVarName = '__vite_injected_original_import_meta_url' + const importMetaResolveVarName = + '__vite_injected_original_import_meta_resolve' const result = await build({ absWorkingDir: process.cwd(), @@ -1949,6 +1957,7 @@ async function bundleConfigFile( 'import.meta.url': importMetaUrlVarName, 'import.meta.dirname': dirnameVarName, 'import.meta.filename': filenameVarName, + 'import.meta.resolve': importMetaResolveVarName, 'import.meta.main': 'false', }, plugins: [ @@ -2015,7 +2024,7 @@ async function bundleConfigFile( setup(build) { build.onLoad({ filter: /\.[cm]?[jt]s$/ }, async (args) => { const contents = await fsp.readFile(args.path, 'utf-8') - const injectValues = + let injectValues = `const ${dirnameVarName} = ${JSON.stringify( path.dirname(args.path), )};` + @@ -2023,6 +2032,17 @@ async function bundleConfigFile( `const ${importMetaUrlVarName} = ${JSON.stringify( pathToFileURL(args.path).href, )};` + if (contents.includes('import.meta.resolve')) { + if (isESM) { + if (!importMetaResolverRegistered) { + importMetaResolverRegistered = true + await createImportMetaResolver() + } + injectValues += `const ${importMetaResolveVarName} = (specifier, importer = ${importMetaUrlVarName}) => (${importMetaResolveWithCustomHookString})(specifier, importer);` + } else { + injectValues += `const ${importMetaResolveVarName} = (specifier, importer = ${importMetaUrlVarName}) => { throw new Error('import.meta.resolve is not supported in CJS config files') };` + } + } return { loader: args.path.endsWith('ts') ? 'ts' : 'js', diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d0711d0387ca5e..7430f6d0228a84 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -451,6 +451,8 @@ importers: specifier: link:../plugin-module-condition version: link:../plugin-module-condition + packages/vite/src/node/__tests__/fixtures/config/import-meta: {} + packages/vite/src/node/__tests__/fixtures/config/plugin-module-condition: {} packages/vite/src/node/__tests__/fixtures/config/siblings: