From 81aa087fc775ef94f31fbc63e9b8f0a53b52d69c Mon Sep 17 00:00:00 2001 From: Alec Larson <1925840+aleclarson@users.noreply.github.com> Date: Wed, 7 Apr 2021 19:19:54 -0400 Subject: [PATCH 1/5] fix: ignore ENOENT in `injectSourcesContent` This is important for virtual modules and malformed source maps, both of which can throw ENOENT errors when injecting `sourcesContent`. --- packages/vite/src/node/server/sourcemap.ts | 24 +++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/packages/vite/src/node/server/sourcemap.ts b/packages/vite/src/node/server/sourcemap.ts index 5e11f8491443e4..d461170b395e43 100644 --- a/packages/vite/src/node/server/sourcemap.ts +++ b/packages/vite/src/node/server/sourcemap.ts @@ -5,16 +5,26 @@ export async function injectSourcesContent( map: { sources: string[]; sourcesContent?: string[]; sourceRoot?: string }, file: string ): Promise { - const sourceRoot = await fs.realpath( - path.resolve(path.dirname(file), map.sourceRoot || '') - ) + try { + var sourceRoot = await fs.realpath( + path.resolve(path.dirname(file), map.sourceRoot || '') + ) + } catch (e) { + if (e.code == 'ENOENT') return + throw e + } map.sourcesContent = [] await Promise.all( map.sources.filter(Boolean).map(async (sourcePath, i) => { - map.sourcesContent![i] = await fs.readFile( - path.resolve(sourceRoot, decodeURI(sourcePath)), - 'utf-8' - ) + try { + map.sourcesContent![i] = await fs.readFile( + path.resolve(sourceRoot, decodeURI(sourcePath)), + 'utf-8' + ) + } catch (e) { + if (e.code == 'ENOENT') return + throw e + } }) ) } From 143d5b0fa67d6928904ba149810559008841c6e6 Mon Sep 17 00:00:00 2001 From: Alec Larson <1925840+aleclarson@users.noreply.github.com> Date: Fri, 25 Jun 2021 12:00:36 -0400 Subject: [PATCH 2/5] fix: avoid swallowing ENOENT errors for malformed source paths Also, when the `file` is a virtual module, assume source paths are already absolute. --- packages/vite/src/node/server/sourcemap.ts | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/packages/vite/src/node/server/sourcemap.ts b/packages/vite/src/node/server/sourcemap.ts index d461170b395e43..a57012de9829ee 100644 --- a/packages/vite/src/node/server/sourcemap.ts +++ b/packages/vite/src/node/server/sourcemap.ts @@ -10,21 +10,17 @@ export async function injectSourcesContent( path.resolve(path.dirname(file), map.sourceRoot || '') ) } catch (e) { - if (e.code == 'ENOENT') return - throw e + if (e.code !== 'ENOENT') throw e + var isVirtual = true } map.sourcesContent = [] await Promise.all( map.sources.filter(Boolean).map(async (sourcePath, i) => { - try { - map.sourcesContent![i] = await fs.readFile( - path.resolve(sourceRoot, decodeURI(sourcePath)), - 'utf-8' - ) - } catch (e) { - if (e.code == 'ENOENT') return - throw e + sourcePath = decodeURI(sourcePath) + if (!isVirtual) { + sourcePath = path.resolve(sourceRoot, sourcePath) } + map.sourcesContent![i] = await fs.readFile(sourcePath, 'utf-8') }) ) } From f379c96754d37073b915d9c1b6c69644ca477d8e Mon Sep 17 00:00:00 2001 From: Alec Larson <1925840+aleclarson@users.noreply.github.com> Date: Fri, 25 Jun 2021 12:01:42 -0400 Subject: [PATCH 3/5] fix: throw a clearer error for non-existent sources --- packages/vite/src/node/server/sourcemap.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/vite/src/node/server/sourcemap.ts b/packages/vite/src/node/server/sourcemap.ts index a57012de9829ee..0447dfc80dfd6f 100644 --- a/packages/vite/src/node/server/sourcemap.ts +++ b/packages/vite/src/node/server/sourcemap.ts @@ -20,7 +20,13 @@ export async function injectSourcesContent( if (!isVirtual) { sourcePath = path.resolve(sourceRoot, sourcePath) } - map.sourcesContent![i] = await fs.readFile(sourcePath, 'utf-8') + try { + map.sourcesContent![i] = await fs.readFile(sourcePath, 'utf-8') + } catch (e) { + throw new Error( + `Sourcemap for "${file}" has a non-existent source: "${sourcePath}"` + ) + } }) ) } From ba1871ed901b83b690d0ac062b0556fd4d376144 Mon Sep 17 00:00:00 2001 From: Alec Larson <1925840+aleclarson@users.noreply.github.com> Date: Tue, 20 Jul 2021 20:50:37 -0400 Subject: [PATCH 4/5] feat: warn once per sourcemap with missing source files --- packages/vite/src/node/server/sourcemap.ts | 57 ++++++++++++------- .../vite/src/node/server/transformRequest.ts | 2 +- 2 files changed, 39 insertions(+), 20 deletions(-) diff --git a/packages/vite/src/node/server/sourcemap.ts b/packages/vite/src/node/server/sourcemap.ts index 0447dfc80dfd6f..abfbc5c82ec45e 100644 --- a/packages/vite/src/node/server/sourcemap.ts +++ b/packages/vite/src/node/server/sourcemap.ts @@ -1,32 +1,51 @@ -import { promises as fs } from 'fs' import path from 'path' +import { promises as fs } from 'fs' +import { Logger } from '../logger' +import { createDebugger } from '../utils' + +const isDebug = !!process.env.DEBUG +const debug = createDebugger('vite:sourcemap', { + onlyWhenFocused: true +}) + +interface SourceMapLike { + sources: string[] + sourcesContent?: (string | null)[] + sourceRoot?: string +} export async function injectSourcesContent( - map: { sources: string[]; sourcesContent?: string[]; sourceRoot?: string }, - file: string + map: SourceMapLike, + file: string, + logger: Logger ): Promise { + let sourceRoot: string | undefined try { - var sourceRoot = await fs.realpath( + // The source root is undefined for virtual modules and permission errors. + sourceRoot = await fs.realpath( path.resolve(path.dirname(file), map.sourceRoot || '') ) - } catch (e) { - if (e.code !== 'ENOENT') throw e - var isVirtual = true - } - map.sourcesContent = [] - await Promise.all( - map.sources.filter(Boolean).map(async (sourcePath, i) => { + } catch {} + + const missingSources: string[] = [] + map.sourcesContent = await Promise.all( + map.sources.filter(Boolean).map((sourcePath) => { sourcePath = decodeURI(sourcePath) - if (!isVirtual) { + if (sourceRoot) { sourcePath = path.resolve(sourceRoot, sourcePath) } - try { - map.sourcesContent![i] = await fs.readFile(sourcePath, 'utf-8') - } catch (e) { - throw new Error( - `Sourcemap for "${file}" has a non-existent source: "${sourcePath}"` - ) - } + return fs.readFile(sourcePath, 'utf-8').catch(() => { + missingSources.push(sourcePath) + return null + }) }) ) + + // Use this command… + // DEBUG="vite:sourcemap" vite build + // …to log the missing sources. + if (missingSources.length) { + logger.warnOnce(`Sourcemap for "${file}" points to missing source files`) + isDebug && debug(`Missing sources:\n ` + missingSources.join(`\n `)) + } } diff --git a/packages/vite/src/node/server/transformRequest.ts b/packages/vite/src/node/server/transformRequest.ts index ebb29dc461ea72..483df46d06e6e5 100644 --- a/packages/vite/src/node/server/transformRequest.ts +++ b/packages/vite/src/node/server/transformRequest.ts @@ -147,7 +147,7 @@ export async function transformRequest( if (map && mod.file) { map = (typeof map === 'string' ? JSON.parse(map) : map) as SourceMap if (map.mappings && !map.sourcesContent) { - await injectSourcesContent(map, mod.file) + await injectSourcesContent(map, mod.file, logger) } } From ed09cb765019a9052b444ea036dc17027133b8eb Mon Sep 17 00:00:00 2001 From: Alec Larson <1925840+aleclarson@users.noreply.github.com> Date: Tue, 20 Jul 2021 20:51:37 -0400 Subject: [PATCH 5/5] fix(sourcemap): ensure `sources` and `sourcesContent` are the same length --- packages/vite/src/node/server/sourcemap.ts | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/packages/vite/src/node/server/sourcemap.ts b/packages/vite/src/node/server/sourcemap.ts index abfbc5c82ec45e..515b5a605a3157 100644 --- a/packages/vite/src/node/server/sourcemap.ts +++ b/packages/vite/src/node/server/sourcemap.ts @@ -29,15 +29,18 @@ export async function injectSourcesContent( const missingSources: string[] = [] map.sourcesContent = await Promise.all( - map.sources.filter(Boolean).map((sourcePath) => { - sourcePath = decodeURI(sourcePath) - if (sourceRoot) { - sourcePath = path.resolve(sourceRoot, sourcePath) + map.sources.map((sourcePath) => { + if (sourcePath) { + sourcePath = decodeURI(sourcePath) + if (sourceRoot) { + sourcePath = path.resolve(sourceRoot, sourcePath) + } + return fs.readFile(sourcePath, 'utf-8').catch(() => { + missingSources.push(sourcePath) + return null + }) } - return fs.readFile(sourcePath, 'utf-8').catch(() => { - missingSources.push(sourcePath) - return null - }) + return null }) )