From 1da7c93e4a6438a99f1f9339aa62ac51468b6fab Mon Sep 17 00:00:00 2001 From: Junseo Kim Date: Thu, 3 Sep 2026 23:56:54 +0900 Subject: [PATCH 1/2] fix(nextjs): Prevent sourceMappingURL stripping from truncating minified chunks The regex in stripSourceMappingURLComments did not require the comment to start at a line start, so sourceMappingURL-shaped text inside a string literal of a minified (single-line) chunk matched, and everything from the marker to EOF was deleted, leaving the chunk unparseable. Anchor the match to a line start and exclude whitespace/quote characters from the URL, matching how debug-id-upload.ts already reads the comment. --- packages/nextjs/src/config/handleRunAfterProductionCompile.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nextjs/src/config/handleRunAfterProductionCompile.ts b/packages/nextjs/src/config/handleRunAfterProductionCompile.ts index ae4b0a91d84a..8c8ed4af3ed8 100644 --- a/packages/nextjs/src/config/handleRunAfterProductionCompile.ts +++ b/packages/nextjs/src/config/handleRunAfterProductionCompile.ts @@ -137,8 +137,8 @@ async function warnAboutUncoveredSourcemaps( } } -const SOURCEMAPPING_URL_COMMENT_REGEX = /\n?\/\/[#@] sourceMappingURL=[^\n]+$/; -const CSS_SOURCEMAPPING_URL_COMMENT_REGEX = /\n?\/\*[#@] sourceMappingURL=[^\n]+\*\/$/; +const SOURCEMAPPING_URL_COMMENT_REGEX = /(?:^|\n)\/\/[#@] sourceMappingURL=[^\s'"`]+$/; +const CSS_SOURCEMAPPING_URL_COMMENT_REGEX = /(?:^|\n)\/\*[#@] sourceMappingURL=[^\n]+\*\/$/; /** * Strips sourceMappingURL comments from all JS/MJS/CJS/CSS files in the given directory. From 9d762850fcc4084608c6b8a7bc096bed8aaeaf8f Mon Sep 17 00:00:00 2001 From: Junseo Kim Date: Thu, 3 Sep 2026 23:56:54 +0900 Subject: [PATCH 2/2] test(nextjs): Cover string-embedded sourceMappingURL markers in strip tests --- .../handleRunAfterProductionCompile.test.ts | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/packages/nextjs/test/config/handleRunAfterProductionCompile.test.ts b/packages/nextjs/test/config/handleRunAfterProductionCompile.test.ts index ebff37a09c5a..5da39a04b2d0 100644 --- a/packages/nextjs/test/config/handleRunAfterProductionCompile.test.ts +++ b/packages/nextjs/test/config/handleRunAfterProductionCompile.test.ts @@ -740,4 +740,46 @@ describe('stripSourceMappingURLComments', () => { expect(content).not.toContain('sourceMappingURL'); } }); + + it('does not modify minified files with a sourceMappingURL marker inside a string literal', async () => { + const filePath = path.join(tmpDir, 'chunks', 'minified.js'); + const originalContent = `const worker = 'self.onmessage = () => {};\\n//# sourceMappingURL=worker.js.map\\n'; use(worker);`; + await fs.promises.writeFile(filePath, originalContent); + + await stripSourceMappingURLComments(tmpDir); + + const content = await fs.promises.readFile(filePath, 'utf-8'); + expect(content).toBe(originalContent); + }); + + it('does not modify files ending with a template literal containing a sourceMappingURL marker', async () => { + const filePath = path.join(tmpDir, 'chunks', 'template.js'); + const originalContent = 'const s = `line1\n//# sourceMappingURL=worker.js.map`;'; + await fs.promises.writeFile(filePath, originalContent); + + await stripSourceMappingURLComments(tmpDir); + + const content = await fs.promises.readFile(filePath, 'utf-8'); + expect(content).toBe(originalContent); + }); + + it('strips sourceMappingURL comment from files consisting only of the comment', async () => { + const filePath = path.join(tmpDir, 'chunks', 'comment-only.js'); + await fs.promises.writeFile(filePath, '//# sourceMappingURL=comment-only.js.map'); + + await stripSourceMappingURLComments(tmpDir); + + const content = await fs.promises.readFile(filePath, 'utf-8'); + expect(content).toBe(''); + }); + + it('strips sourceMappingURL comment with a data: URI', async () => { + const filePath = path.join(tmpDir, 'chunks', 'inline.js'); + await fs.promises.writeFile(filePath, 'var a = 1;\n//# sourceMappingURL=data:application/json;base64,eyJ2IjozfQ=='); + + await stripSourceMappingURLComments(tmpDir); + + const content = await fs.promises.readFile(filePath, 'utf-8'); + expect(content).toBe('var a = 1;'); + }); });