Skip to content

Commit 1cbc24d

Browse files
authoredDec 20, 2022
fix: don't resolve builtin Node modules (#2538)
* fix: use "node:" prefix in Vitest imports * chore: add test for prefix * chore: cleanup * chore: use more node protocol * chore: cleanup * chore: cleanup
1 parent 7ae1417 commit 1cbc24d

39 files changed

+112
-60
lines changed
 

‎packages/browser/rollup.config.js

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const external = [
1010
...Object.keys(pkg.dependencies),
1111
...Object.keys(pkg.peerDependencies || {}),
1212
'worker_threads',
13+
'node:worker_threads',
1314
]
1415

1516
const plugins = [

‎packages/ui/rollup.config.js

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const external = [
1212
...Object.keys(pkg.dependencies),
1313
...Object.keys(pkg.peerDependencies || {}),
1414
'worker_threads',
15+
'node:worker_threads',
1516
'vitest/node',
1617
'vitest',
1718
]

‎packages/vite-node/rollup.config.js

+12-8
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,11 @@ const external = [
2626
'pathe',
2727
'birpc',
2828
'vite',
29-
'url',
30-
'events',
29+
'node:url',
30+
'node:events',
3131
]
3232

3333
const plugins = [
34-
alias({
35-
entries: [
36-
{ find: /^node:(.+)$/, replacement: '$1' },
37-
],
38-
}),
3934
resolve({
4035
preferBuiltins: true,
4136
}),
@@ -68,7 +63,16 @@ export default defineConfig([
6863
chunkFileNames: 'chunk-[name].cjs',
6964
},
7065
external,
71-
plugins,
66+
plugins: [
67+
alias({
68+
entries: [
69+
// cjs in Node 14 doesn't support node: prefix
70+
// can be dropped, when we drop support for Node 14
71+
{ find: /^node:(.+)$/, replacement: '$1' },
72+
],
73+
}),
74+
...plugins,
75+
],
7276
onwarn,
7377
},
7478
{

‎packages/vite-node/src/client.ts

+10-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import { createRequire } from 'module'
1+
import { createRequire } from 'node:module'
22
// we need native dirname, because windows __dirname has \\
3-
// eslint-disable-next-line no-restricted-imports
4-
import { dirname } from 'path'
5-
import { fileURLToPath, pathToFileURL } from 'url'
6-
import vm from 'vm'
3+
import { dirname } from 'node:path'
4+
import { fileURLToPath, pathToFileURL } from 'node:url'
5+
import vm from 'node:vm'
6+
import { isNodeBuiltin } from 'mlly'
77
import { resolve } from 'pathe'
88
import createDebug from 'debug'
99
import { VALID_ID_PREFIX, cleanUrl, isInternalRequest, isPrimitive, normalizeModuleId, normalizeRequestId, slash, toFilePath } from './utils'
@@ -190,8 +190,12 @@ export class ViteNodeRunner {
190190
}
191191
}
192192

193+
shouldResolveId(id: string, _importee?: string) {
194+
return !isInternalRequest(id) && !isNodeBuiltin(id)
195+
}
196+
193197
async resolveUrl(id: string, importee?: string): Promise<[url: string, fsPath: string]> {
194-
if (isInternalRequest(id))
198+
if (!this.shouldResolveId(id))
195199
return [id, id]
196200
// we don't pass down importee here, because otherwise Vite doesn't resolve it correctly
197201
if (importee && id.startsWith(VALID_ID_PREFIX))

‎packages/vite-node/src/debug.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* eslint-disable no-console */
2-
import { existsSync, promises as fs } from 'fs'
2+
import { existsSync, promises as fs } from 'node:fs'
33
import { join, resolve } from 'pathe'
44
import type { TransformResult } from 'vite'
55
import c from 'picocolors'

‎packages/vite-node/src/externalize.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { existsSync } from 'fs'
1+
import { existsSync } from 'node:fs'
22
import { isNodeBuiltin, isValidNodeImport } from 'mlly'
33
import type { DepsHandlingOptions } from './types'
44
import { slash } from './utils'

‎packages/vite-node/src/hmr/emitter.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { EventEmitter } from 'events'
1+
import { EventEmitter } from 'node:events'
22
import type { HMRPayload, Plugin } from 'vite'
33

44
export type EventType = string | symbol

‎packages/vite-node/src/server.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { performance } from 'perf_hooks'
1+
import { performance } from 'node:perf_hooks'
22
import { resolve } from 'pathe'
33
import type { TransformResult, ViteDevServer } from 'vite'
44
import createDebug from 'debug'

‎packages/vite-node/src/utils.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { fileURLToPath, pathToFileURL } from 'url'
2-
import { existsSync } from 'fs'
1+
import { fileURLToPath, pathToFileURL } from 'node:url'
2+
import { existsSync } from 'node:fs'
33
import { resolve } from 'pathe'
44
import type { Arrayable, Nullable } from './types'
55

@@ -23,7 +23,7 @@ export function normalizeRequestId(id: string, base?: string): string {
2323
.replace(/^\/@id\/__x00__/, '\0') // virtual modules start with `\0`
2424
.replace(/^\/@id\//, '')
2525
.replace(/^__vite-browser-external:/, '')
26-
.replace(/^(node|file):/, '')
26+
.replace(/^file:/, '')
2727
.replace(/^\/+/, '/') // remove duplicate leading slashes
2828
.replace(/\?v=\w+/, '?') // remove ?v= query
2929
.replace(/&v=\w+/, '') // remove &v= query
@@ -50,6 +50,7 @@ export function normalizeModuleId(id: string) {
5050
.replace(/\\/g, '/')
5151
.replace(/^\/@fs\//, isWindows ? '' : '/')
5252
.replace(/^file:\//, '/')
53+
.replace(/^node:/, '')
5354
.replace(/^\/+/, '/')
5455
}
5556

‎packages/vitest/rollup.config.js

+2-9
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import dts from 'rollup-plugin-dts'
66
import nodeResolve from '@rollup/plugin-node-resolve'
77
import commonjs from '@rollup/plugin-commonjs'
88
import json from '@rollup/plugin-json'
9-
import alias from '@rollup/plugin-alias'
109
import license from 'rollup-plugin-license'
1110
import c from 'picocolors'
1211
import fg from 'fast-glob'
@@ -41,6 +40,8 @@ const external = [
4140
...Object.keys(pkg.dependencies),
4241
...Object.keys(pkg.peerDependencies),
4342
'worker_threads',
43+
'node:worker_threads',
44+
'node:fs',
4445
'inspector',
4546
'vite-node/source-map',
4647
'vite-node/client',
@@ -49,14 +50,6 @@ const external = [
4950
]
5051

5152
const plugins = [
52-
alias({
53-
entries: [
54-
{ find: /^node:(.+)$/, replacement: '$1' },
55-
{ find: 'vite-node/server', replacement: resolve(__dirname, '../vite-node/src/server.ts') },
56-
{ find: 'vite-node/client', replacement: resolve(__dirname, '../vite-node/src/client.ts') },
57-
{ find: 'vite-node/utils', replacement: resolve(__dirname, '../vite-node/src/utils.ts') },
58-
],
59-
}),
6053
nodeResolve({
6154
preferBuiltins: true,
6255
}),

‎packages/vitest/src/api/setup.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { promises as fs } from 'fs'
1+
import { promises as fs } from 'node:fs'
22
import type { BirpcReturn } from 'birpc'
33
import { createBirpc } from 'birpc'
44
import { parse, stringify } from 'flatted'

‎packages/vitest/src/constants.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import url from 'url'
1+
import url from 'node:url'
22
import { resolve } from 'pathe'
33
import { isNode } from './utils/env'
44

‎packages/vitest/src/integrations/env/node.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Console } from 'console'
1+
import { Console } from 'node:console'
22
import type { Environment } from '../../types'
33

44
export default <Environment>({

‎packages/vitest/src/integrations/snapshot/port/state.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* LICENSE file in the root directory of this source tree.
66
*/
77

8-
import fs from 'fs'
8+
import fs from 'node:fs'
99
import type { OptionsReceived as PrettyFormatOptions } from 'pretty-format'
1010
import type { ParsedStack, SnapshotData, SnapshotMatchOptions, SnapshotResult, SnapshotStateOptions, SnapshotUpdateState } from '../../../types'
1111
import { slash } from '../../../utils'

‎packages/vitest/src/integrations/snapshot/port/utils.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* LICENSE file in the root directory of this source tree.
66
*/
77

8-
import fs from 'fs'
8+
import fs from 'node:fs'
99
import { dirname, join } from 'pathe'
1010
import naturalCompare from 'natural-compare'
1111
import type { OptionsReceived as PrettyFormatOptions } from 'pretty-format'

‎packages/vitest/src/node/cache/files.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import fs from 'fs'
2-
import type { Stats } from 'fs'
1+
import fs from 'node:fs'
2+
import type { Stats } from 'node:fs'
33

44
type FileStatsCache = Pick<Stats, 'size'>
55

‎packages/vitest/src/node/cache/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import fs from 'fs'
1+
import fs from 'node:fs'
22
import { findUp } from 'find-up'
33
import { resolve } from 'pathe'
44
import { loadConfigFromFile } from 'vite'

‎packages/vitest/src/node/cache/results.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import fs from 'fs'
1+
import fs from 'node:fs'
22
import { dirname, resolve } from 'pathe'
33
import type { File, ResolvedConfig } from '../../types'
44
import { version } from '../../../package.json'

‎packages/vitest/src/node/core.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { existsSync, promises as fs } from 'fs'
1+
import { existsSync, promises as fs } from 'node:fs'
22
import type { ViteDevServer } from 'vite'
33
import { normalizePath } from 'vite'
44
import { relative, toNamespacedPath } from 'pathe'

‎packages/vitest/src/node/pool.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { MessageChannel } from 'worker_threads'
2-
import _url from 'url'
3-
import { cpus } from 'os'
1+
import { MessageChannel } from 'node:worker_threads'
2+
import _url from 'node:url'
3+
import { cpus } from 'node:os'
44
import { resolve } from 'pathe'
55
import type { Options as TinypoolOptions } from 'tinypool'
66
import { Tinypool } from 'tinypool'

‎packages/vitest/src/node/reporters/benchmark/json.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { existsSync, promises as fs } from 'fs'
1+
import { existsSync, promises as fs } from 'node:fs'
22
import { dirname, resolve } from 'pathe'
33
import type { Vitest } from '../../../node'
44
import type { BenchTaskResult, File, Reporter } from '../../../types'

‎packages/vitest/src/node/reporters/json.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { existsSync, promises as fs } from 'fs'
1+
import { existsSync, promises as fs } from 'node:fs'
22
import { dirname, resolve } from 'pathe'
33
import type { Vitest } from '../../node'
44
import type { File, Reporter, Suite, Task, TaskState } from '../../types'

‎packages/vitest/src/node/reporters/junit.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { existsSync, promises as fs } from 'fs'
2-
import { hostname } from 'os'
1+
import { existsSync, promises as fs } from 'node:fs'
2+
import { hostname } from 'node:os'
33
import { dirname, relative, resolve } from 'pathe'
44

55
import type { Vitest } from '../../node'

‎packages/vitest/src/runtime/entry.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { promises as fs } from 'fs'
1+
import { promises as fs } from 'node:fs'
22
import type { EnvironmentOptions, ResolvedConfig, VitestEnvironment } from '../types'
33
import { getWorkerState, resetModules } from '../utils'
44
import { vi } from '../integrations/vi'

‎packages/vitest/src/runtime/execute.ts

+11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { ViteNodeRunner } from 'vite-node/client'
2+
import { isInternalRequest } from 'vite-node/utils'
23
import type { ViteNodeRunnerOptions } from 'vite-node'
34
import { normalizePath } from 'vite'
5+
import { isNodeBuiltin } from 'mlly'
46
import type { MockMap } from '../types/mocker'
57
import { getCurrentEnvironment, getWorkerState } from '../utils'
68
import { VitestMocker } from './mocker'
@@ -31,6 +33,15 @@ export class VitestRunner extends ViteNodeRunner {
3133
this.mocker = new VitestMocker(this)
3234
}
3335

36+
shouldResolveId(id: string, _importee?: string | undefined): boolean {
37+
if (isInternalRequest(id))
38+
return false
39+
const environment = getCurrentEnvironment()
40+
// do not try and resolve node builtins in Node
41+
// import('url') returns Node internal even if 'url' package is installed
42+
return environment === 'node' ? !isNodeBuiltin(id) : true
43+
}
44+
3445
async resolveUrl(id: string, importee?: string) {
3546
if (importee && importee.startsWith('mock:'))
3647
importee = importee.slice(5)

‎packages/vitest/src/runtime/loader.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { pathToFileURL } from 'url'
2-
import { readFile } from 'fs/promises'
1+
import { pathToFileURL } from 'node:url'
2+
import { readFile } from 'node:fs/promises'
33
import { hasCJSSyntax, isNodeBuiltin } from 'mlly'
44
import { normalizeModuleId } from 'vite-node/utils'
55
import { getWorkerState } from '../utils'

‎packages/vitest/src/runtime/mocker.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { existsSync, readdirSync } from 'fs'
1+
import { existsSync, readdirSync } from 'node:fs'
22
import { isNodeBuiltin } from 'mlly'
33
import { basename, dirname, extname, isAbsolute, join, resolve } from 'pathe'
44
import c from 'picocolors'

‎packages/vitest/src/runtime/setup.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ export async function setupConsoleLogSpy() {
5050
const timers = new Map<string, { stdoutTime: number; stderrTime: number; timer: any }>()
5151
const unknownTestId = '__vitest__unknown_test__'
5252

53-
const { Writable } = await import('stream')
54-
const { Console } = await import('console')
53+
const { Writable } = await import('node:stream')
54+
const { Console } = await import('node:console')
5555

5656
// group sync console.log calls with macro task
5757
function schedule(taskId: string) {

‎packages/vitest/src/typecheck/typechecker.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { rm } from 'fs/promises'
1+
import { rm } from 'node:fs/promises'
22
import type { ExecaChildProcess } from 'execa'
33
import { execa } from 'execa'
44
import { resolve } from 'pathe'

‎packages/vitest/src/types/worker.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { MessagePort } from 'worker_threads'
1+
import type { MessagePort } from 'node:worker_threads'
22
import type { FetchFunction, ModuleCacheMap, RawSourceMap, ViteNodeResolveId } from 'vite-node'
33
import type { BirpcReturn } from 'birpc'
44
import type { MockMap } from './mocker'

‎packages/vitest/src/utils/index.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
// eslint-disable-next-line no-restricted-imports
2-
import { relative as relativeBrowser } from 'path'
1+
import { relative as relativeBrowser } from 'node:path'
32
import c from 'picocolors'
43
import { isPackageExists } from 'local-pkg'
54
import { relative as relativeNode } from 'pathe'

‎packages/web-worker/src/shared-worker.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { MessageChannel, type MessagePort as NodeMessagePort } from 'worker_threads'
1+
import { MessageChannel, type MessagePort as NodeMessagePort } from 'node:worker_threads'
22
import type { InlineWorkerContext, Procedure } from './types'
33
import { InlineWorkerRunner } from './runner'
44
import { debug, getRunnerOptions } from './utils'

‎packages/ws-client/rollup.config.js

+2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ const external = [
1313
'ws',
1414
'birpc',
1515
'worker_threads',
16+
'node:worker_threads',
1617
'fs',
18+
'node:fs',
1719
'vitest',
1820
'inspector',
1921
]

‎pnpm-lock.yaml

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎scripts/update-contributors.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { promises as fs } from 'fs'
1+
import { promises as fs } from 'node:fs'
22
import { $fetch } from 'ohmyfetch'
33

44
interface Contributor {

‎test/benchmark/test.mjs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { readFile } from 'fs/promises'
1+
import { readFile } from 'node:fs/promises'
22
import { execa } from 'execa'
33

44
let error

‎test/core/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
},
88
"devDependencies": {
99
"tinyspy": "^1.0.2",
10+
"url": "^0.11.0",
1011
"vitest": "workspace:*"
1112
}
1213
}
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// @vitest-environment jsdom
2+
3+
// outdated url package, which Vite will resolve to, if "url" import is used
4+
// this should help catch bugs in source code
5+
import packageUrl from 'url'
6+
import nodeUrl from 'node:url'
7+
import { expect, it } from 'vitest'
8+
9+
it('vitest resolves url to installed url package, but node:url to internal Node module', () => {
10+
expect(packageUrl).not.toHaveProperty('URL')
11+
expect(packageUrl).not.toHaveProperty('URLSearchParams')
12+
expect(packageUrl).not.toHaveProperty('fileURLToPath')
13+
expect(nodeUrl).toHaveProperty('URL')
14+
expect(nodeUrl).toHaveProperty('URLSearchParams')
15+
expect(nodeUrl).toHaveProperty('fileURLToPath')
16+
// eslint-disable-next-line n/no-deprecated-api
17+
expect(packageUrl.parse !== nodeUrl.parse).toBe(true)
18+
})
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// @vitest-environment node
2+
3+
import packageUrl from 'url'
4+
import nodeUrl from 'node:url'
5+
import { expect, it } from 'vitest'
6+
7+
it('vitest resolves both "url" and "node:url" to internal URL module in Node environment', () => {
8+
expect(packageUrl).toHaveProperty('URL')
9+
expect(packageUrl).toHaveProperty('URLSearchParams')
10+
expect(packageUrl).toHaveProperty('fileURLToPath')
11+
expect(nodeUrl).toHaveProperty('URL')
12+
expect(nodeUrl).toHaveProperty('URLSearchParams')
13+
expect(nodeUrl).toHaveProperty('fileURLToPath')
14+
expect(packageUrl.URL === nodeUrl.URL).toBe(true)
15+
})

0 commit comments

Comments
 (0)
Please sign in to comment.