From 60f155245e2615682745fd7d6247e2e6c863e6c1 Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Wed, 14 Jun 2023 19:15:39 +0900 Subject: [PATCH 1/5] fix: breakpoints in JS not working --- packages/vite/src/node/server/send.ts | 5 +++++ playground/css-sourcemap/__tests__/css-sourcemap.spec.ts | 3 +-- playground/js-sourcemap/__tests__/js-sourcemap.spec.ts | 3 +-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/vite/src/node/server/send.ts b/packages/vite/src/node/server/send.ts index aadebd1628885c..4195384ff91853 100644 --- a/packages/vite/src/node/server/send.ts +++ b/packages/vite/src/node/server/send.ts @@ -5,6 +5,7 @@ import type { } from 'node:http' import getEtag from 'etag' import type { SourceMap } from 'rollup' +import { removeTimestampQuery } from '../utils' import { getCodeWithSourcemap } from './sourcemap' const alias: Record = { @@ -60,6 +61,10 @@ export function send( if (type === 'js' || type === 'css') { content = getCodeWithSourcemap(type, content.toString(), map) } + } else { + if (type === 'js') { + content += `\n//# sourceURL=${removeTimestampQuery(req.url!)}` + } } res.statusCode = 200 diff --git a/playground/css-sourcemap/__tests__/css-sourcemap.spec.ts b/playground/css-sourcemap/__tests__/css-sourcemap.spec.ts index 82d862c7ad7d82..6706b5dcaae510 100644 --- a/playground/css-sourcemap/__tests__/css-sourcemap.spec.ts +++ b/playground/css-sourcemap/__tests__/css-sourcemap.spec.ts @@ -82,8 +82,7 @@ describe.runIf(isServe)('serve', () => { new URL('./linked-with-import.css', page.url()).href, ) const content = await res.text() - const lines = content.trim().split('\n') - expect(lines[lines.length - 1]).not.toMatch(/^\/\/#/) + expect(content).not.toMatch('//#s*sourceMappingURL') }, ) diff --git a/playground/js-sourcemap/__tests__/js-sourcemap.spec.ts b/playground/js-sourcemap/__tests__/js-sourcemap.spec.ts index ce67f19e904521..a7429c8f486958 100644 --- a/playground/js-sourcemap/__tests__/js-sourcemap.spec.ts +++ b/playground/js-sourcemap/__tests__/js-sourcemap.spec.ts @@ -13,8 +13,7 @@ if (!isBuild) { test('js', async () => { const res = await page.request.get(new URL('./foo.js', page.url()).href) const js = await res.text() - const lines = js.split('\n') - expect(lines[lines.length - 1].includes('//')).toBe(false) // expect no sourcemap + expect(js).not.toContain('sourceMappingURL') }) test('ts', async () => { From 95ffb785bf0910a6877460d82e72bf31c7da0471 Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Fri, 16 Jun 2023 14:50:49 +0900 Subject: [PATCH 2/5] wip: use sourcemap --- packages/vite/rollup.config.ts | 2 +- packages/vite/src/node/server/send.ts | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/vite/rollup.config.ts b/packages/vite/rollup.config.ts index 6884b6f15f378f..026288950e87c0 100644 --- a/packages/vite/rollup.config.ts +++ b/packages/vite/rollup.config.ts @@ -195,7 +195,7 @@ function createCjsConfig(isProduction: boolean) { ...Object.keys(pkg.dependencies), ...(isProduction ? [] : Object.keys(pkg.devDependencies)), ], - plugins: [...createNodePlugins(false, false, false), bundleSizeLimit(120)], + plugins: [...createNodePlugins(false, false, false), bundleSizeLimit(150)], }) } diff --git a/packages/vite/src/node/server/send.ts b/packages/vite/src/node/server/send.ts index 4195384ff91853..33a3026e59c6a0 100644 --- a/packages/vite/src/node/server/send.ts +++ b/packages/vite/src/node/server/send.ts @@ -5,6 +5,7 @@ import type { } from 'node:http' import getEtag from 'etag' import type { SourceMap } from 'rollup' +import MagicString from 'magic-string' import { removeTimestampQuery } from '../utils' import { getCodeWithSourcemap } from './sourcemap' @@ -63,7 +64,15 @@ export function send( } } else { if (type === 'js') { - content += `\n//# sourceURL=${removeTimestampQuery(req.url!)}` + const urlWithoutTimestamp = removeTimestampQuery(req.url!) + if (req.url! !== urlWithoutTimestamp) { + const ms = new MagicString(content.toString()) + content = getCodeWithSourcemap( + type, + content.toString(), + ms.generateMap({ source: urlWithoutTimestamp, hires: true }), + ) + } } } From 06c3d3b40216e24405ac4fa7cf2c6fa1ea1932f8 Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Sat, 12 Aug 2023 16:54:12 +0900 Subject: [PATCH 3/5] wip: use sourcemap --- packages/vite/src/node/server/send.ts | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/vite/src/node/server/send.ts b/packages/vite/src/node/server/send.ts index 33a3026e59c6a0..d6db2f4d963d7e 100644 --- a/packages/vite/src/node/server/send.ts +++ b/packages/vite/src/node/server/send.ts @@ -63,16 +63,14 @@ export function send( content = getCodeWithSourcemap(type, content.toString(), map) } } else { - if (type === 'js') { + if (type === 'js' && (!map || map.mappings !== '')) { const urlWithoutTimestamp = removeTimestampQuery(req.url!) - if (req.url! !== urlWithoutTimestamp) { - const ms = new MagicString(content.toString()) - content = getCodeWithSourcemap( - type, - content.toString(), - ms.generateMap({ source: urlWithoutTimestamp, hires: true }), - ) - } + const ms = new MagicString(content.toString()) + content = getCodeWithSourcemap( + type, + content.toString(), + ms.generateMap({ source: urlWithoutTimestamp, hires: 'boundary' }), + ) } } From 1690dc317e286c6df44c996ad6e9981b9f7e52b3 Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Sat, 12 Aug 2023 16:54:31 +0900 Subject: [PATCH 4/5] wip: support `{ mappings: '' }` --- packages/vite/src/node/server/index.ts | 4 +- .../src/node/server/middlewares/indexHtml.ts | 2 +- .../vite/src/node/server/pluginContainer.ts | 45 ++++++++++++------- packages/vite/src/node/server/send.ts | 4 +- .../vite/src/node/server/transformRequest.ts | 32 ++++++++----- packages/vite/src/node/ssr/ssrModuleLoader.ts | 2 +- packages/vite/src/node/ssr/ssrTransform.ts | 13 ++++-- 7 files changed, 64 insertions(+), 38 deletions(-) diff --git a/packages/vite/src/node/server/index.ts b/packages/vite/src/node/server/index.ts index 67b455735b7be8..d1c83bf43a7b91 100644 --- a/packages/vite/src/node/server/index.ts +++ b/packages/vite/src/node/server/index.ts @@ -235,7 +235,7 @@ export interface ViteDevServer { */ ssrTransform( code: string, - inMap: SourceMap | null, + inMap: SourceMap | { mappings: '' } | null, url: string, originalCode?: string, ): Promise @@ -385,7 +385,7 @@ export async function _createServer( resolvedUrls: null, // will be set on listen ssrTransform( code: string, - inMap: SourceMap | null, + inMap: SourceMap | { mappings: '' } | null, url: string, originalCode = code, ) { diff --git a/packages/vite/src/node/server/middlewares/indexHtml.ts b/packages/vite/src/node/server/middlewares/indexHtml.ts index bc9ddb3f5f93ab..678c09fc7c029c 100644 --- a/packages/vite/src/node/server/middlewares/indexHtml.ts +++ b/packages/vite/src/node/server/middlewares/indexHtml.ts @@ -282,7 +282,7 @@ const devHtmlHook: IndexHtmlTransformHook = async ( const result = await server!.pluginContainer.transform(code, mod.id!) let content = '' if (result) { - if (result.map) { + if (result.map && 'version' in result.map) { if (result.map.mappings) { await injectSourcesContent( result.map, diff --git a/packages/vite/src/node/server/pluginContainer.ts b/packages/vite/src/node/server/pluginContainer.ts index d900ba55aa68af..6db3589f2d84e2 100644 --- a/packages/vite/src/node/server/pluginContainer.ts +++ b/packages/vite/src/node/server/pluginContainer.ts @@ -132,7 +132,7 @@ export interface PluginContainer { inMap?: SourceDescription['map'] ssr?: boolean }, - ): Promise<{ code: string; map: SourceMap | null }> + ): Promise<{ code: string; map: SourceMap | { mappings: '' } | null }> load( id: string, options?: { @@ -481,7 +481,7 @@ export async function createPluginContainer( typeof err.loc?.column === 'number' ) { const rawSourceMap = ctx._getCombinedSourcemap() - if (rawSourceMap) { + if (rawSourceMap && 'version' in rawSourceMap) { const traced = new TraceMap(rawSourceMap as any) const { source, line, column } = originalPositionFor(traced, { line: Number(err.loc.line), @@ -525,7 +525,7 @@ export async function createPluginContainer( originalCode: string originalSourcemap: SourceMap | null = null sourcemapChain: NonNullable[] = [] - combinedMap: SourceMap | null = null + combinedMap: SourceMap | { mappings: '' } | null = null constructor(filename: string, code: string, inMap?: SourceMap | string) { super() @@ -540,7 +540,7 @@ export async function createPluginContainer( } } - _getCombinedSourcemap(createIfNull = false) { + _getCombinedSourcemap() { if ( debugSourcemapCombine && debugSourcemapCombineFilter && @@ -553,12 +553,26 @@ export async function createPluginContainer( } let combinedMap = this.combinedMap + // { mappings: '' } + if ( + combinedMap && + !('version' in combinedMap) && + combinedMap.mappings === '' + ) { + this.sourcemapChain.length = 0 + return combinedMap + } + for (let m of this.sourcemapChain) { if (typeof m === 'string') m = JSON.parse(m) if (!('version' in (m as SourceMap))) { + // { mappings: '' } + if ((m as SourceMap).mappings === '') { + combinedMap = { mappings: '' } + break + } // empty, nullified source map - combinedMap = this.combinedMap = null - this.sourcemapChain.length = 0 + combinedMap = null break } if (!combinedMap) { @@ -570,15 +584,6 @@ export async function createPluginContainer( ]) as SourceMap } } - if (!combinedMap) { - return createIfNull - ? new MagicString(this.originalCode).generateMap({ - includeContent: true, - hires: 'boundary', - source: cleanUrl(this.filename), - }) - : null - } if (combinedMap !== this.combinedMap) { this.combinedMap = combinedMap this.sourcemapChain.length = 0 @@ -587,7 +592,15 @@ export async function createPluginContainer( } getCombinedSourcemap() { - return this._getCombinedSourcemap(true) as SourceMap + const map = this._getCombinedSourcemap() + if (!map || (!('version' in map) && map.mappings === '')) { + return new MagicString(this.originalCode).generateMap({ + includeContent: true, + hires: 'boundary', + source: cleanUrl(this.filename), + }) + } + return map } } diff --git a/packages/vite/src/node/server/send.ts b/packages/vite/src/node/server/send.ts index d6db2f4d963d7e..36f70049c47e88 100644 --- a/packages/vite/src/node/server/send.ts +++ b/packages/vite/src/node/server/send.ts @@ -20,7 +20,7 @@ export interface SendOptions { etag?: string cacheControl?: string headers?: OutgoingHttpHeaders - map?: SourceMap | null + map?: SourceMap | { mappings: '' } | null } export function send( @@ -58,7 +58,7 @@ export function send( } // inject source map reference - if (map && map.mappings) { + if (map && 'version' in map && map.mappings) { if (type === 'js' || type === 'css') { content = getCodeWithSourcemap(type, content.toString(), map) } diff --git a/packages/vite/src/node/server/transformRequest.ts b/packages/vite/src/node/server/transformRequest.ts index 1785be47728add..cbc0b768f70198 100644 --- a/packages/vite/src/node/server/transformRequest.ts +++ b/packages/vite/src/node/server/transformRequest.ts @@ -31,7 +31,7 @@ const debugCache = createDebugger('vite:cache') export interface TransformResult { code: string - map: SourceMap | null + map: SourceMap | { mappings: '' } | null etag?: string deps?: string[] dynamicDeps?: string[] @@ -286,15 +286,23 @@ async function loadAndTransform( map = transformResult.map } - if (map && mod.file) { - map = (typeof map === 'string' ? JSON.parse(map) : map) as SourceMap - if (map.mappings) { - await injectSourcesContent(map, mod.file, logger) + let normalizedMap: SourceMap | { mappings: '' } | null + if (typeof map === 'string') { + normalizedMap = JSON.parse(map) + } else if (map) { + normalizedMap = map as SourceMap | { mappings: '' } + } else { + normalizedMap = null + } + + if (normalizedMap && 'version' in normalizedMap && mod.file) { + if (normalizedMap.mappings) { + await injectSourcesContent(normalizedMap, mod.file, logger) } const sourcemapPath = `${mod.file}.map` applySourcemapIgnoreList( - map, + normalizedMap, sourcemapPath, config.server.sourcemapIgnoreList, logger, @@ -303,16 +311,16 @@ async function loadAndTransform( if (path.isAbsolute(mod.file)) { for ( let sourcesIndex = 0; - sourcesIndex < map.sources.length; + sourcesIndex < normalizedMap.sources.length; ++sourcesIndex ) { - const sourcePath = map.sources[sourcesIndex] + const sourcePath = normalizedMap.sources[sourcesIndex] if (sourcePath) { // Rewrite sources to relative paths to give debuggers the chance // to resolve and display them in a meaningful way (rather than // with absolute paths). if (path.isAbsolute(sourcePath)) { - map.sources[sourcesIndex] = path.relative( + normalizedMap.sources[sourcesIndex] = path.relative( path.dirname(mod.file), sourcePath, ) @@ -326,12 +334,12 @@ async function loadAndTransform( const result = ssr && !server.config.experimental.skipSsrTransform - ? await server.ssrTransform(code, map as SourceMap, url, originalCode) + ? await server.ssrTransform(code, normalizedMap, url, originalCode) : ({ code, - map, + map: normalizedMap, etag: getEtag(code, { weak: true }), - } as TransformResult) + } satisfies TransformResult) // Only cache the result if the module wasn't invalidated while it was // being processed, so it is re-processed next time if it is stale diff --git a/packages/vite/src/node/ssr/ssrModuleLoader.ts b/packages/vite/src/node/ssr/ssrModuleLoader.ts index 3e498809f32829..852b2c5fac1041 100644 --- a/packages/vite/src/node/ssr/ssrModuleLoader.ts +++ b/packages/vite/src/node/ssr/ssrModuleLoader.ts @@ -202,7 +202,7 @@ async function instantiateModule( } let sourceMapSuffix = '' - if (result.map) { + if (result.map && 'version' in result.map) { const moduleSourceMap = Object.assign({}, result.map, { // currently we need to offset the line // https://github.com/nodejs/node/issues/43047#issuecomment-1180632750 diff --git a/packages/vite/src/node/ssr/ssrTransform.ts b/packages/vite/src/node/ssr/ssrTransform.ts index 4d77e7972688d3..e13e2dec37d624 100644 --- a/packages/vite/src/node/ssr/ssrTransform.ts +++ b/packages/vite/src/node/ssr/ssrTransform.ts @@ -38,7 +38,7 @@ const hashbangRE = /^#!.*\n/ export async function ssrTransform( code: string, - inMap: SourceMap | null, + inMap: SourceMap | { mappings: '' } | null, url: string, originalCode: string, options?: TransformOptions, @@ -51,7 +51,7 @@ export async function ssrTransform( async function ssrTransformJSON( code: string, - inMap: SourceMap | null, + inMap: SourceMap | { mappings: '' } | null, ): Promise { return { code: code.replace('export default', `${ssrModuleExportsKey}.default =`), @@ -63,7 +63,7 @@ async function ssrTransformJSON( async function ssrTransformScript( code: string, - inMap: SourceMap | null, + inMap: SourceMap | { mappings: '' } | null, url: string, originalCode: string, ): Promise { @@ -275,7 +275,12 @@ async function ssrTransformScript( }) let map = s.generateMap({ hires: 'boundary' }) - if (inMap && inMap.mappings && inMap.sources.length > 0) { + if ( + inMap && + inMap.mappings && + 'sources' in inMap && + inMap.sources.length > 0 + ) { map = combineSourcemaps(url, [ { ...map, From cc70dd45cb2671e7bd23902e087c569c9a0331e7 Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Sat, 12 Aug 2023 17:00:04 +0900 Subject: [PATCH 5/5] wip: update test --- .../js-sourcemap/__tests__/js-sourcemap.spec.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/playground/js-sourcemap/__tests__/js-sourcemap.spec.ts b/playground/js-sourcemap/__tests__/js-sourcemap.spec.ts index a7429c8f486958..5a445252120111 100644 --- a/playground/js-sourcemap/__tests__/js-sourcemap.spec.ts +++ b/playground/js-sourcemap/__tests__/js-sourcemap.spec.ts @@ -13,7 +13,16 @@ if (!isBuild) { test('js', async () => { const res = await page.request.get(new URL('./foo.js', page.url()).href) const js = await res.text() - expect(js).not.toContain('sourceMappingURL') + const map = extractSourcemap(js) + expect(formatSourcemapForSnapshot(map)).toMatchInlineSnapshot(` + { + "mappings": "AAAA,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;", + "sources": [ + "/foo.js", + ], + "version": 3, + } + `) }) test('ts', async () => {