diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a9c8120ed7c0..3e5c80f5e6b8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -107,7 +107,8 @@ jobs: run: pnpm run build - name: Test - run: pnpm run test:ci + run: pnpm -C test/vite-node test + # run: pnpm run test:ci - name: Test Examples run: pnpm run test:examples diff --git a/packages/vite-node/src/hmr/emitter.ts b/packages/vite-node/src/hmr/emitter.ts index 375224f05261..b5e51915f93d 100644 --- a/packages/vite-node/src/hmr/emitter.ts +++ b/packages/vite-node/src/hmr/emitter.ts @@ -1,5 +1,6 @@ import type { HMRPayload, Plugin } from 'vite' import { EventEmitter } from 'node:events' +import { sourceMapCache } from '../source-map-cache' export type EventType = string | symbol export type Handler = (event: T) => void @@ -73,5 +74,9 @@ export function viteNodeHmrPlugin(): Plugin { } } }, + + handleHotUpdate(ctx) { + delete sourceMapCache[ctx.file] + }, } } diff --git a/packages/vite-node/src/server.ts b/packages/vite-node/src/server.ts index 4ad21e03e56a..5a2baa06cf11 100644 --- a/packages/vite-node/src/server.ts +++ b/packages/vite-node/src/server.ts @@ -190,6 +190,7 @@ export class ViteNodeServer { } getSourceMap(source: string) { + source = normalizeModuleId(source) const fetchResult = this.fetchCache.get(source)?.result if (fetchResult?.map) { return fetchResult.map diff --git a/packages/vite-node/src/source-map-cache.ts b/packages/vite-node/src/source-map-cache.ts new file mode 100644 index 000000000000..03da01fdbd72 --- /dev/null +++ b/packages/vite-node/src/source-map-cache.ts @@ -0,0 +1,7 @@ +import type { TraceMap } from '@jridgewell/trace-mapping' + +// Maps a file path to a source map for that file +export const sourceMapCache: Record< + string, + { url: string | null; map: TraceMap | null } +> = {} diff --git a/packages/vite-node/src/source-map-handler.ts b/packages/vite-node/src/source-map-handler.ts index 91729747dc1d..278a53cb076f 100644 --- a/packages/vite-node/src/source-map-handler.ts +++ b/packages/vite-node/src/source-map-handler.ts @@ -10,6 +10,7 @@ import type { import fs from 'node:fs' import path from 'node:path' import { originalPositionFor, TraceMap } from '@jridgewell/trace-mapping' +import { sourceMapCache } from './source-map-cache' // Only install once if called multiple times let errorFormatterInstalled = false @@ -17,12 +18,6 @@ let errorFormatterInstalled = false // Maps a file path to a string containing the file contents const fileContentsCache: Record = {} -// Maps a file path to a source map for that file -const sourceMapCache: Record< - string, - { url: string | null; map: TraceMap | null } -> = {} - // Regex for detecting source maps const reSourceMap = /^data:application\/json[^,]+base64,/ diff --git a/test/vite-node/src/watch/source-map.ts b/test/vite-node/src/watch/source-map.ts new file mode 100644 index 000000000000..81677fe72f24 --- /dev/null +++ b/test/vite-node/src/watch/source-map.ts @@ -0,0 +1,16 @@ +// 1 +// 1 +async function main() { + try { + // 2 + // 2 + throw new Error('boom') + } + catch (e) { + // eslint-disable-next-line no-console + console.log(e) + } +} +// 3 +// 3 +main() diff --git a/test/vite-node/test/cli.test.ts b/test/vite-node/test/cli.test.ts index fea9d13800bb..4a0f725ef8f9 100644 --- a/test/vite-node/test/cli.test.ts +++ b/test/vite-node/test/cli.test.ts @@ -52,3 +52,11 @@ it.each(['index.js', 'index.cjs', 'index.mjs'])('correctly runs --watch %s', asy editFile(entryPath, c => c.replace('test 1', 'test 2')) await viteNode.waitForStdout('test 2') }) + +it('invalidate source map cache', async () => { + const entryPath = resolve(__dirname, '../src/watch/source-map.ts') + const { viteNode } = await runViteNodeCli('--watch', entryPath) + await viteNode.waitForStdout('source-map.ts:7:11') + editFile(entryPath, c => c.replaceAll(' // 2\n', '')) + await viteNode.waitForStdout('source-map.ts:5:11') +})