Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion packages/vite-node/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { extractSourceMap } from './source-map'
import {
cleanUrl,
createImportMetaEnvProxy,
isBareImport,
isInternalRequest,
isNodeBuiltin,
isPrimitive,
Expand Down Expand Up @@ -325,6 +326,25 @@ export class ViteNodeRunner {
return await this.cachedRequest(id, fsPath, callstack)
}

private async _fetchModule(id: string, importer?: string) {
try {
return await this.options.fetchModule(id)
}
catch (cause: any) {
// rethrow vitest error if it cannot load the module because it's not resolved
if (typeof cause?.message === 'string' && cause.message.includes('Failed to load url')) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added an additional check

const error = new Error(
`Cannot find ${isBareImport(id) ? 'package' : 'module'} '${id}'${importer ? ` imported from '${importer}'` : ''}`,
{ cause },
) as Error & { code: string }
error.code = 'ERR_MODULE_NOT_FOUND'
throw error
}

throw cause
}
}

/** @internal */
async directRequest(id: string, fsPath: string, _callstack: string[]) {
const moduleId = normalizeModuleId(fsPath)
Expand All @@ -345,7 +365,10 @@ export class ViteNodeRunner {
if (id in requestStubs) {
return requestStubs[id]
}
let { code: transformed, externalize } = await this.options.fetchModule(id)
let { code: transformed, externalize } = await this._fetchModule(
id,
callstack[callstack.length - 2],
)

if (externalize) {
debugNative(externalize)
Expand Down
6 changes: 6 additions & 0 deletions packages/vite-node/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ export function slash(str: string): string {
return str.replace(/\\/g, '/')
}

const bareImportRE = /^(?![a-z]:)[\w@](?!.*:\/\/)/i

export function isBareImport(id: string): boolean {
return bareImportRE.test(id)
}

export const VALID_ID_PREFIX = '/@id/'

export function normalizeRequestId(id: string, base?: string): string {
Expand Down
4 changes: 2 additions & 2 deletions packages/vitest/src/runtime/external-executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import fs from 'node:fs'
import { dirname } from 'node:path'
import { fileURLToPath, pathToFileURL } from 'node:url'
import { extname, join, normalize } from 'pathe'
import { getCachedData, isNodeBuiltin, setCacheData } from 'vite-node/utils'
import { getCachedData, isBareImport, isNodeBuiltin, setCacheData } from 'vite-node/utils'
import { CommonjsExecutor } from './vm/commonjs-executor'
import { EsmExecutor } from './vm/esm-executor'
import { ViteExecutor } from './vm/vite-executor'
Expand Down Expand Up @@ -209,7 +209,7 @@ export class ExternalModulesExecutor {
(type === 'module' || type === 'commonjs' || type === 'wasm')
&& !existsSync(path)
) {
const error = new Error(`Cannot find module '${path}'`);
const error = new Error(`Cannot find ${isBareImport(path) ? 'package' : 'module'} '${path}'`);
(error as any).code = 'ERR_MODULE_NOT_FOUND'
throw error
}
Expand Down
26 changes: 20 additions & 6 deletions packages/vitest/src/runtime/vm/vite-executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,27 @@ export class ViteExecutor {
return cached
}
return this.esm.createEsModule(fileUrl, async () => {
const result = await this.options.transform(fileUrl, 'web')
if (!result.code) {
throw new Error(
`[vitest] Failed to transform ${fileUrl}. Does the file exist?`,
)
try {
const result = await this.options.transform(fileUrl, 'web')
if (result.code) {
return result.code
}
}
return result.code
catch (cause: any) {
// rethrow vitest error if it cannot load the module because it's not resolved
if (typeof cause?.message === 'string' && cause.message.includes('Failed to load url')) {
const error = new Error(
`Cannot find module '${fileUrl}'`,
{ cause },
) as Error & { code: string }
error.code = 'ERR_MODULE_NOT_FOUND'
throw error
}
}

throw new Error(
`[vitest] Failed to transform ${fileUrl}. Does the file exist?`,
)
})
}

Expand Down
4 changes: 2 additions & 2 deletions test/cli/fixtures/vm-threads/not-found.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ it('package', async () => {
it('builtin', async () => {
await expect(() => notFound.importBuiltin()).rejects.toMatchObject({
code: 'ERR_MODULE_NOT_FOUND',
message: 'Cannot find module \'node:non-existing-builtin\'',
message: 'Cannot find package \'node:non-existing-builtin\'',
})
})

Expand All @@ -31,6 +31,6 @@ it('builtin', async () => {
it('namespace', async () => {
await expect(() => notFound.importNamespace()).rejects.toMatchObject({
code: 'ERR_MODULE_NOT_FOUND',
message: 'Cannot find module \'non-existing-namespace:xyz\'',
message: 'Cannot find package \'non-existing-namespace:xyz\'',
})
})
14 changes: 14 additions & 0 deletions test/core/test/dynamic-import.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { expect, test } from 'vitest'

test('dynamic import', async () => {
try {
await import('non-existing-module' as any)
expect.unreachable()
}
catch (err: any) {
expect(err.message).toBe(
`Cannot find package 'non-existing-module' imported from '${import.meta.filename}'`,
)
expect(err.code).toBe('ERR_MODULE_NOT_FOUND')
}
})
4 changes: 2 additions & 2 deletions test/core/test/imports.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,9 @@ test('dynamic import has null prototype', async () => {
test('dynamic import throws an error', async () => {
const path = './some-unknown-path'
const imported = import(path)
await expect(imported).rejects.toThrowError(/Failed to load url \.\/some-unknown-path/)
await expect(imported).rejects.toThrowError(/Cannot find module '\.\/some-unknown-path' imported/)
// @ts-expect-error path does not exist
await expect(() => import('./some-unknown-path')).rejects.toThrowError(/Failed to load/)
await expect(() => import('./some-unknown-path')).rejects.toThrowError(/Cannot find module/)
})

test('can import @vite/client', async () => {
Expand Down
4 changes: 2 additions & 2 deletions test/core/test/web-worker-jsdom.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ it('worker with invalid url throws an error', async () => {
if (!import.meta.env.VITEST_VM_POOL) {
expect(event.error).toBeInstanceOf(Error)
}
expect(event.error.message).toContain('Failed to load')
expect(event.error.message).toContain('Cannot find module')
})

it('throws an error on invalid path', async () => {
Expand All @@ -34,7 +34,7 @@ it('throws an error on invalid path', async () => {
if (!import.meta.env.VITEST_VM_POOL) {
expect(event.error).toBeInstanceOf(Error)
}
expect(event.error.message).toContain('Failed to load')
expect(event.error.message).toContain('Cannot find module')
})

it('returns globals on self correctly', async () => {
Expand Down
Loading