Skip to content

Commit 79a50c3

Browse files
authoredFeb 6, 2024
fix(vm): improve error when module is not found (#5053)
1 parent 5b1021d commit 79a50c3

File tree

3 files changed

+60
-1
lines changed

3 files changed

+60
-1
lines changed
 

‎packages/vitest/src/runtime/external-executor.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import vm from 'node:vm'
44
import { fileURLToPath, pathToFileURL } from 'node:url'
55
import { dirname } from 'node:path'
6-
import { statSync } from 'node:fs'
6+
import { existsSync, statSync } from 'node:fs'
77
import { extname, join, normalize } from 'pathe'
88
import { getCachedData, isNodeBuiltin, setCacheData } from 'vite-node/utils'
99
import type { RuntimeRPC } from '../types/rpc'
@@ -188,6 +188,14 @@ export class ExternalModulesExecutor {
188188
private async createModule(identifier: string): Promise<VMModule> {
189189
const { type, url, path } = this.getModuleInformation(identifier)
190190

191+
// create ERR_MODULE_NOT_FOUND on our own since latest NodeJS's import.meta.resolve doesn't throw on non-existing namespace or path
192+
// https://github.com/nodejs/node/pull/49038
193+
if ((type === 'module' || type === 'commonjs') && !existsSync(path)) {
194+
const error = new Error(`Cannot find module '${path}'`)
195+
;(error as any).code = 'ERR_MODULE_NOT_FOUND'
196+
throw error
197+
}
198+
191199
switch (type) {
192200
case 'data':
193201
return this.esm.createDataModule(identifier)
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
export async function importPackage() {
2+
await import('@vitest/non-existing-package')
3+
}
4+
5+
export async function importPath() {
6+
await import('./non-existing-path')
7+
}
8+
9+
export async function importBuiltin() {
10+
await import('node:non-existing-builtin')
11+
}
12+
13+
export async function importNamespace() {
14+
await import('non-existing-namespace:xyz')
15+
}
+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { expect, it } from 'vitest'
2+
3+
// @ts-expect-error untyped
4+
import * as notFound from '../src/external/not-found.js'
5+
6+
it('path', async () => {
7+
await expect(() => notFound.importPath()).rejects.toMatchObject({
8+
code: 'ERR_MODULE_NOT_FOUND',
9+
message: expect.stringMatching(/Cannot find module '.*?non-existing-path'/),
10+
})
11+
})
12+
13+
// NodeJs's import.meta.resolve throws ERR_MODULE_NOT_FOUND error only this case.
14+
// For other cases, similar errors are fabricated by Vitest to mimic NodeJs's behavior.
15+
it('package', async () => {
16+
await expect(() => notFound.importPackage()).rejects.toMatchObject({
17+
code: 'ERR_MODULE_NOT_FOUND',
18+
message: expect.stringContaining('Cannot find package \'@vitest/non-existing-package\''),
19+
})
20+
})
21+
22+
it('builtin', async () => {
23+
await expect(() => notFound.importBuiltin()).rejects.toMatchObject({
24+
code: 'ERR_MODULE_NOT_FOUND',
25+
message: 'Cannot find module \'node:non-existing-builtin\'',
26+
})
27+
})
28+
29+
// this test fails before node 20.3.0 since it throws a different error (cf. https://github.com/nodejs/node/pull/47824)
30+
// > Only URLs with a scheme in: file and data are supported by the default ESM loader. Received protocol 'non-existing-namespace:'
31+
it('namespace', async () => {
32+
await expect(() => notFound.importNamespace()).rejects.toMatchObject({
33+
code: 'ERR_MODULE_NOT_FOUND',
34+
message: 'Cannot find module \'non-existing-namespace:xyz\'',
35+
})
36+
})

0 commit comments

Comments
 (0)
Please sign in to comment.