From a764cb2744ae1502cf615117be5cb132d4281af9 Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Fri, 13 Jan 2023 13:58:42 +0100 Subject: [PATCH 1/9] fix: don't resolve import paths, if they are already resolved --- packages/vite-node/src/client.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/vite-node/src/client.ts b/packages/vite-node/src/client.ts index b49d43f9dc28..50ec0f262367 100644 --- a/packages/vite-node/src/client.ts +++ b/packages/vite-node/src/client.ts @@ -4,7 +4,7 @@ import { dirname } from 'node:path' import { fileURLToPath, pathToFileURL } from 'node:url' import vm from 'node:vm' import { isNodeBuiltin } from 'mlly' -import { resolve } from 'pathe' +import { isAbsolute, resolve } from 'pathe' import createDebug from 'debug' import { VALID_ID_PREFIX, cleanUrl, isInternalRequest, isPrimitive, normalizeModuleId, normalizeRequestId, slash, toFilePath } from './utils' import type { HotContext, ModuleCache, ViteNodeRunnerOptions } from './types' @@ -213,7 +213,8 @@ export class ViteNodeRunner { if (importee && id.startsWith(VALID_ID_PREFIX)) importee = undefined id = normalizeRequestId(id, this.options.base) - if (!this.options.resolveId) + // absolute IDs are already resolved by Vite analyzer + if (!this.options.resolveId || isAbsolute(id)) return [id, toFilePath(id, this.root)] const resolved = await this.options.resolveId(id, importee) const resolvedId = resolved @@ -278,7 +279,6 @@ export class ViteNodeRunner { if (id in requestStubs) return requestStubs[id] - // eslint-disable-next-line prefer-const let { code: transformed, externalize } = await this.options.fetchModule(id) if (externalize) { From 614ae0e6d999067152cf2be58e416308cf4bc772 Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Fri, 13 Jan 2023 14:27:51 +0100 Subject: [PATCH 2/9] chore: another way to improve performance of resolveId --- packages/vite-node/src/client.ts | 4 ++-- packages/vite-node/src/server.ts | 14 +++++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/vite-node/src/client.ts b/packages/vite-node/src/client.ts index 50ec0f262367..4513dd00077b 100644 --- a/packages/vite-node/src/client.ts +++ b/packages/vite-node/src/client.ts @@ -4,7 +4,7 @@ import { dirname } from 'node:path' import { fileURLToPath, pathToFileURL } from 'node:url' import vm from 'node:vm' import { isNodeBuiltin } from 'mlly' -import { isAbsolute, resolve } from 'pathe' +import { resolve } from 'pathe' import createDebug from 'debug' import { VALID_ID_PREFIX, cleanUrl, isInternalRequest, isPrimitive, normalizeModuleId, normalizeRequestId, slash, toFilePath } from './utils' import type { HotContext, ModuleCache, ViteNodeRunnerOptions } from './types' @@ -214,7 +214,7 @@ export class ViteNodeRunner { importee = undefined id = normalizeRequestId(id, this.options.base) // absolute IDs are already resolved by Vite analyzer - if (!this.options.resolveId || isAbsolute(id)) + if (!this.options.resolveId) return [id, toFilePath(id, this.root)] const resolved = await this.options.resolveId(id, importee) const resolvedId = resolved diff --git a/packages/vite-node/src/server.ts b/packages/vite-node/src/server.ts index f8e1c10d42fe..aa67dd0b4e5d 100644 --- a/packages/vite-node/src/server.ts +++ b/packages/vite-node/src/server.ts @@ -1,5 +1,5 @@ import { performance } from 'node:perf_hooks' -import { resolve } from 'pathe' +import { isAbsolute, join, resolve } from 'pathe' import type { TransformResult, ViteDevServer } from 'vite' import createDebug from 'debug' import type { DebuggerOptions, FetchResult, RawSourceMap, ViteNodeResolveId, ViteNodeServerOptions } from './types' @@ -65,6 +65,18 @@ export class ViteNodeServer { } async resolveId(id: string, importer?: string): Promise { + if (id.startsWith('/@fs/')) + return { id: id.slice(4) } + if (isAbsolute(id)) { + const moduleMap = this.server.moduleGraph.idToModuleMap + const mod = moduleMap.get(id) + if (mod?.file) + return { id: mod.file } + const fsPath = join(this.server.config.root, id) + const fsMod = moduleMap.get(fsPath) + if (fsMod?.file) + return { id: fsMod.file } + } if (importer && !importer.startsWith(this.server.config.root)) importer = resolve(this.server.config.root, importer) const mode = (importer && this.getTransformMode(importer)) || 'ssr' From 0102c40e4f1af1fb7413dff89b06086a79dc8ee1 Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Fri, 13 Jan 2023 14:31:31 +0100 Subject: [PATCH 3/9] chore: cleanup --- packages/vite-node/src/client.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/vite-node/src/client.ts b/packages/vite-node/src/client.ts index 4513dd00077b..e9951460d0ca 100644 --- a/packages/vite-node/src/client.ts +++ b/packages/vite-node/src/client.ts @@ -213,7 +213,6 @@ export class ViteNodeRunner { if (importee && id.startsWith(VALID_ID_PREFIX)) importee = undefined id = normalizeRequestId(id, this.options.base) - // absolute IDs are already resolved by Vite analyzer if (!this.options.resolveId) return [id, toFilePath(id, this.root)] const resolved = await this.options.resolveId(id, importee) From 7f126b1fe9ab3c80a5cb25b9bcc41bea8cda3cf2 Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Fri, 13 Jan 2023 14:33:09 +0100 Subject: [PATCH 4/9] chore: cleanup --- packages/vite-node/src/server.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/vite-node/src/server.ts b/packages/vite-node/src/server.ts index aa67dd0b4e5d..5b9578adf0ce 100644 --- a/packages/vite-node/src/server.ts +++ b/packages/vite-node/src/server.ts @@ -69,13 +69,11 @@ export class ViteNodeServer { return { id: id.slice(4) } if (isAbsolute(id)) { const moduleMap = this.server.moduleGraph.idToModuleMap - const mod = moduleMap.get(id) - if (mod?.file) - return { id: mod.file } + if (moduleMap.has(id)) + return { id } const fsPath = join(this.server.config.root, id) - const fsMod = moduleMap.get(fsPath) - if (fsMod?.file) - return { id: fsMod.file } + if (moduleMap.has(fsPath)) + return { id: fsPath } } if (importer && !importer.startsWith(this.server.config.root)) importer = resolve(this.server.config.root, importer) From 87dace8df0211496b682156d276f7801c50decbc Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Fri, 13 Jan 2023 14:39:51 +0100 Subject: [PATCH 5/9] test: cleanup --- test/core/test/imports.test.ts | 11 ++++++++++- test/vite-node/test/server.test.ts | 3 +++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/test/core/test/imports.test.ts b/test/core/test/imports.test.ts index eed2418e2640..874f236b0c30 100644 --- a/test/core/test/imports.test.ts +++ b/test/core/test/imports.test.ts @@ -28,7 +28,7 @@ test('dynamic aliased import works', async () => { expect(stringTimeoutMod).toBe(variableTimeoutMod) }) -test('dynamic absolute import works', async () => { +test('dynamic absolute from root import works', async () => { const stringTimeoutMod = await import('./../src/timeout') const timeoutPath = '/src/timeout' @@ -37,6 +37,15 @@ test('dynamic absolute import works', async () => { expect(stringTimeoutMod).toBe(variableTimeoutMod) }) +test('dynamic absolute with extension mport works', async () => { + const stringTimeoutMod = await import('./../src/timeout') + + const timeoutPath = '/src/timeout.ts' + const variableTimeoutMod = await import(timeoutPath) + + expect(stringTimeoutMod).toBe(variableTimeoutMod) +}) + test('data with dynamic import works', async () => { const dataUri = 'data:text/javascript;charset=utf-8,export default "hi"' const { default: hi } = await import(dataUri) diff --git a/test/vite-node/test/server.test.ts b/test/vite-node/test/server.test.ts index cdb9ca1fcbfc..a7f165371110 100644 --- a/test/vite-node/test/server.test.ts +++ b/test/vite-node/test/server.test.ts @@ -10,6 +10,9 @@ describe('server works correctly', async () => { config: { root: '/', }, + moduleGraph: { + idToModuleMap: new Map(), + }, } as any, { transformMode: { web: [/web/], From 622981ee9098841f42bc8c59ab5c334e9b03e6dd Mon Sep 17 00:00:00 2001 From: Vladimir Date: Fri, 13 Jan 2023 15:01:26 +0100 Subject: [PATCH 6/9] chore: fix windows --- packages/vite-node/src/server.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/vite-node/src/server.ts b/packages/vite-node/src/server.ts index 5b9578adf0ce..6d53bec0fc5a 100644 --- a/packages/vite-node/src/server.ts +++ b/packages/vite-node/src/server.ts @@ -4,7 +4,7 @@ import type { TransformResult, ViteDevServer } from 'vite' import createDebug from 'debug' import type { DebuggerOptions, FetchResult, RawSourceMap, ViteNodeResolveId, ViteNodeServerOptions } from './types' import { shouldExternalize } from './externalize' -import { normalizeModuleId, toArray, toFilePath } from './utils' +import { isWindows, normalizeModuleId, toArray, toFilePath } from './utils' import { Debugger } from './debug' import { withInlineSourcemap } from './source-map' @@ -66,7 +66,8 @@ export class ViteNodeServer { async resolveId(id: string, importer?: string): Promise { if (id.startsWith('/@fs/')) - return { id: id.slice(4) } + // remove "/" on windows, because the first letter should be drive + return { id: id.slice(isWindows ? 5 : 4) } if (isAbsolute(id)) { const moduleMap = this.server.moduleGraph.idToModuleMap if (moduleMap.has(id)) From 32e49e698a6de801df900024bedaf814681ff79f Mon Sep 17 00:00:00 2001 From: Vladimir Date: Fri, 13 Jan 2023 15:05:30 +0100 Subject: [PATCH 7/9] chore: cleanup --- packages/vite-node/src/server.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/vite-node/src/server.ts b/packages/vite-node/src/server.ts index 6d53bec0fc5a..a5111d4c0415 100644 --- a/packages/vite-node/src/server.ts +++ b/packages/vite-node/src/server.ts @@ -4,7 +4,7 @@ import type { TransformResult, ViteDevServer } from 'vite' import createDebug from 'debug' import type { DebuggerOptions, FetchResult, RawSourceMap, ViteNodeResolveId, ViteNodeServerOptions } from './types' import { shouldExternalize } from './externalize' -import { isWindows, normalizeModuleId, toArray, toFilePath } from './utils' +import { isWindows, normalizeModuleId, slash, toArray, toFilePath } from './utils' import { Debugger } from './debug' import { withInlineSourcemap } from './source-map' @@ -65,9 +65,10 @@ export class ViteNodeServer { } async resolveId(id: string, importer?: string): Promise { - if (id.startsWith('/@fs/')) - // remove "/" on windows, because the first letter should be drive - return { id: id.slice(isWindows ? 5 : 4) } + if (id.startsWith('/@fs/')) { + const fsPath = slash(id.slice(4)) + return { id: isWindows ? fsPath.slice(1) : fsPath } + } if (isAbsolute(id)) { const moduleMap = this.server.moduleGraph.idToModuleMap if (moduleMap.has(id)) From 2db1c4be1ceeb7559d2ecbdcf237519d36660c7b Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Fri, 13 Jan 2023 17:03:45 +0100 Subject: [PATCH 8/9] refactor: improve toFilePath instead --- packages/vite-node/src/client.ts | 7 ++++--- packages/vite-node/src/server.ts | 18 +++--------------- packages/vite-node/src/utils.ts | 24 +++++++++++++----------- test/core/test/file-path.test.ts | 16 ++++++++-------- 4 files changed, 28 insertions(+), 37 deletions(-) diff --git a/packages/vite-node/src/client.ts b/packages/vite-node/src/client.ts index e9951460d0ca..de78b7d6a012 100644 --- a/packages/vite-node/src/client.ts +++ b/packages/vite-node/src/client.ts @@ -213,14 +213,15 @@ export class ViteNodeRunner { if (importee && id.startsWith(VALID_ID_PREFIX)) importee = undefined id = normalizeRequestId(id, this.options.base) - if (!this.options.resolveId) - return [id, toFilePath(id, this.root)] + const { path, exists } = toFilePath(id, this.root) + if (!this.options.resolveId || exists) + return [id, path] const resolved = await this.options.resolveId(id, importee) const resolvedId = resolved ? normalizeRequestId(resolved.id, this.options.base) : id // to be compatible with dependencies that do not resolve id - const fsPath = resolved ? resolvedId : toFilePath(id, this.root) + const fsPath = resolved ? resolvedId : path return [resolvedId, fsPath] } diff --git a/packages/vite-node/src/server.ts b/packages/vite-node/src/server.ts index a5111d4c0415..9a067208406e 100644 --- a/packages/vite-node/src/server.ts +++ b/packages/vite-node/src/server.ts @@ -1,10 +1,10 @@ import { performance } from 'node:perf_hooks' -import { isAbsolute, join, resolve } from 'pathe' +import { resolve } from 'pathe' import type { TransformResult, ViteDevServer } from 'vite' import createDebug from 'debug' import type { DebuggerOptions, FetchResult, RawSourceMap, ViteNodeResolveId, ViteNodeServerOptions } from './types' import { shouldExternalize } from './externalize' -import { isWindows, normalizeModuleId, slash, toArray, toFilePath } from './utils' +import { normalizeModuleId, toArray, toFilePath } from './utils' import { Debugger } from './debug' import { withInlineSourcemap } from './source-map' @@ -65,18 +65,6 @@ export class ViteNodeServer { } async resolveId(id: string, importer?: string): Promise { - if (id.startsWith('/@fs/')) { - const fsPath = slash(id.slice(4)) - return { id: isWindows ? fsPath.slice(1) : fsPath } - } - if (isAbsolute(id)) { - const moduleMap = this.server.moduleGraph.idToModuleMap - if (moduleMap.has(id)) - return { id } - const fsPath = join(this.server.config.root, id) - if (moduleMap.has(fsPath)) - return { id: fsPath } - } if (importer && !importer.startsWith(this.server.config.root)) importer = resolve(this.server.config.root, importer) const mode = (importer && this.getTransformMode(importer)) || 'ssr' @@ -137,7 +125,7 @@ export class ViteNodeServer { private async _fetchModule(id: string): Promise { let result: FetchResult - const filePath = toFilePath(id, this.server.config.root) + const { path: filePath } = toFilePath(id, this.server.config.root) const module = this.server.moduleGraph.getModuleById(id) const timestamp = module ? module.lastHMRTimestamp : null diff --git a/packages/vite-node/src/utils.ts b/packages/vite-node/src/utils.ts index e11f22f6ffaf..29df281b2a93 100644 --- a/packages/vite-node/src/utils.ts +++ b/packages/vite-node/src/utils.ts @@ -61,27 +61,29 @@ export function isPrimitive(v: any) { return v !== Object(v) } -export function toFilePath(id: string, root: string): string { - let absolute = (() => { +export function toFilePath(id: string, root: string): { path: string; exists: boolean } { + let { absolute, exists } = (() => { if (id.startsWith('/@fs/')) - return id.slice(4) + return { absolute: id.slice(4), exists: true } + // check if /src/module.js -> /src/module.js if (!id.startsWith(root) && id.startsWith('/')) { const resolved = resolve(root, id.slice(1)) - // The resolved path can have query values. Remove them before checking - // the file path. - if (existsSync(resolved.replace(/\?.*$/, ''))) - return resolved + if (existsSync(cleanUrl(resolved))) + return { absolute: resolved, exists: true } } - return id + return { absolute: id, exists: false } })() if (absolute.startsWith('//')) absolute = absolute.slice(1) // disambiguate the `:/` on windows: see nodejs/node#31710 - return isWindows && absolute.startsWith('/') - ? slash(fileURLToPath(pathToFileURL(absolute.slice(1)).href)) - : absolute + return { + path: isWindows && absolute.startsWith('/') + ? slash(fileURLToPath(pathToFileURL(absolute.slice(1)).href)) + : absolute, + exists, + } } /** diff --git a/test/core/test/file-path.test.ts b/test/core/test/file-path.test.ts index c0b1a4f37319..98a59ec75091 100644 --- a/test/core/test/file-path.test.ts +++ b/test/core/test/file-path.test.ts @@ -82,7 +82,7 @@ describe('toFilePath', () => { const expected = 'C:/path/to/project/node_modules/pkg/file.js' const processSpy = vi.spyOn(process, 'cwd').mockReturnValue(root) - const filePath = toFilePath(id, root) + const { path: filePath } = toFilePath(id, root) processSpy.mockRestore() expect(slash(filePath)).toEqual(expected) @@ -94,7 +94,7 @@ describe('toFilePath', () => { const expected = 'C:/path/to/project/node_modules/pkg/file.js' const processSpy = vi.spyOn(process, 'cwd').mockReturnValue(root) - const filePath = toFilePath(id, root) + const { path: filePath } = toFilePath(id, root) processSpy.mockRestore() expect(slash(filePath)).toEqual(expected) @@ -110,7 +110,7 @@ describe('toFilePath', () => { const processSpy = vi.spyOn(process, 'cwd').mockReturnValue(root) const existsSpy = vi.mocked(existsSync).mockReturnValue(true) - const filePath = toFilePath(id, root) + const { path: filePath } = toFilePath(id, root) processSpy.mockRestore() existsSpy.mockRestore() @@ -124,7 +124,7 @@ describe('toFilePath', () => { const processSpy = vi.spyOn(process, 'cwd').mockReturnValue(root) const existsSpy = vi.mocked(existsSync).mockReturnValue(true) - const filePath = toFilePath(id, root) + const { path: filePath } = toFilePath(id, root) processSpy.mockRestore() existsSpy.mockRestore() @@ -138,7 +138,7 @@ describe('toFilePath', () => { const processSpy = vi.spyOn(process, 'cwd').mockReturnValue(root) const existsSpy = vi.mocked(existsSync).mockReturnValue(true) - const filePath = toFilePath(id, root) + const { path: filePath } = toFilePath(id, root) processSpy.mockRestore() existsSpy.mockRestore() @@ -152,7 +152,7 @@ describe('toFilePath', () => { const processSpy = vi.spyOn(process, 'cwd').mockReturnValue(root) const existsSpy = vi.mocked(existsSync).mockReturnValue(true) - const filePath = toFilePath(id, root) + const { path: filePath } = toFilePath(id, root) processSpy.mockRestore() existsSpy.mockRestore() @@ -166,7 +166,7 @@ describe('toFilePath', () => { const processSpy = vi.spyOn(process, 'cwd').mockReturnValue(root) const existsSpy = vi.mocked(existsSync).mockReturnValue(true) - const filePath = toFilePath(id, root) + const { path: filePath } = toFilePath(id, root) processSpy.mockRestore() existsSpy.mockRestore() @@ -179,7 +179,7 @@ describe('toFilePath', () => { const processSpy = vi.spyOn(process, 'cwd').mockReturnValue(root) const existsSpy = vi.mocked(existsSync).mockReturnValue(false) - const filePath = toFilePath(id, root) + const { path: filePath } = toFilePath(id, root) processSpy.mockRestore() existsSpy.mockRestore() From c7ec3803a022dce70a319e57594082cb3f3ab71a Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Fri, 13 Jan 2023 17:20:57 +0100 Subject: [PATCH 9/9] chore: check if starts with root --- packages/vite-node/src/utils.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/vite-node/src/utils.ts b/packages/vite-node/src/utils.ts index 29df281b2a93..424acf1d43fd 100644 --- a/packages/vite-node/src/utils.ts +++ b/packages/vite-node/src/utils.ts @@ -71,6 +71,9 @@ export function toFilePath(id: string, root: string): { path: string; exists: bo if (existsSync(cleanUrl(resolved))) return { absolute: resolved, exists: true } } + else if (id.startsWith(root) && existsSync(cleanUrl(id))) { + return { absolute: id, exists: true } + } return { absolute: id, exists: false } })()