Skip to content

Commit f9b3952

Browse files
committed
fix #4078: prepend namespaces to source map paths
1 parent ccf3dd7 commit f9b3952

File tree

3 files changed

+68
-0
lines changed

3 files changed

+68
-0
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212

1313
This fix was contributed by [@jridgewell](https://github.com/jridgewell).
1414

15+
* Fix a regression with non-file source map paths ([#4078](https://github.com/evanw/esbuild/issues/4078))
16+
17+
The format of paths in source maps that aren't in the `file` namespace was unintentionally changed in version 0.25.0. Path namespaces is an esbuild-specific concept that is optionally available for plugins to use to distinguish paths from `file` paths and from paths meant for other plugins. Previously the namespace was prepended to the path joined with a `:` character, but version 0.25.0 unintentionally failed to prepend the namespace. The previous behavior has been restored.
18+
1519
* Fix a crash with `switch` optimization ([#4088](https://github.com/evanw/esbuild/issues/4088))
1620

1721
The new code in the previous release to optimize dead code in switch statements accidentally introduced a crash in the edge case where one or more switch case values include a function expression. This is because esbuild now visits the case values first to determine whether any cases are dead code, and then visits the case values once the dead code status is known. That triggered some internal asserts that guard against traversing the AST in an unexpected order. This crash has been fixed by changing esbuild to expect the new traversal ordering. Here's an example of affected code:

internal/linker/linker.go

+32
Original file line numberDiff line numberDiff line change
@@ -6980,7 +6980,39 @@ func (c *linkerContext) generateSourceMapForChunk(
69806980
}
69816981
source := file.InputFile.Source.KeyPath.Text
69826982
if file.InputFile.Source.KeyPath.Namespace == "file" {
6983+
// Serialize the file path as a "file://" URL, since source maps encode
6984+
// sources as URLs. While we could output absolute "file://" URLs, it
6985+
// will be turned into a relative path when it's written out below for
6986+
// better readability and to be independent of build directory.
69836987
source = helpers.FileURLFromFilePath(source).String()
6988+
} else {
6989+
// If the path for this file isn't in the "file" namespace, then write
6990+
// out something arbitrary instead. Source maps encode sources as URLs
6991+
// but plugins are allowed to put almost anything in the "namespace"
6992+
// and "path" fields, so we don't attempt to control whether this forms
6993+
// a valid URL or not.
6994+
//
6995+
// The approach used here is to join the namespace with the path text
6996+
// using a ":" character. It's important to include the namespace
6997+
// because esbuild considers paths with different namespaces to have
6998+
// separate identities. And using a ":" means that the path is more
6999+
// likely to form a valid URL in the source map.
7000+
//
7001+
// For example, you could imagine a plugin that uses the "https"
7002+
// namespace and path text like "//example.com/foo.js", which would
7003+
// then be joined into the URL "https://example.com/foo.js" here.
7004+
//
7005+
// Note that this logic is currently mostly the same as the pretty-
7006+
// printed paths that esbuild shows to humans in error messages.
7007+
// However, this code has been forked below as these source map URLs
7008+
// are intended for code instead of humans, and we don't want the
7009+
// changes for humans to unintentionally break code that uses them.
7010+
//
7011+
// See https://github.com/evanw/esbuild/issues/4078 for more info.
7012+
if ns := file.InputFile.Source.KeyPath.Namespace; ns != "" {
7013+
source = fmt.Sprintf("%s:%s", ns, source)
7014+
}
7015+
source += file.InputFile.Source.KeyPath.IgnoredSuffix
69847016
}
69857017
items = append(items, item{
69867018
source: source,

scripts/plugin-tests.js

+32
Original file line numberDiff line numberDiff line change
@@ -2675,6 +2675,38 @@ console.log(foo_default, foo_default2);
26752675
}],
26762676
})
26772677
},
2678+
2679+
async sourceMapNamespacePrefixIssue4078({ esbuild, testDir }) {
2680+
const entry = path.join(testDir, 'entry.js')
2681+
await writeFileAsync(entry, `
2682+
import 'foo'
2683+
console.log('entry')
2684+
`)
2685+
2686+
const result = await esbuild.build({
2687+
entryPoints: [entry],
2688+
bundle: true,
2689+
sourcemap: true,
2690+
write: false,
2691+
outdir: path.join(testDir, 'out'),
2692+
plugins: [{
2693+
name: 'example',
2694+
setup(build) {
2695+
build.onResolve({ filter: /foo/ }, () => {
2696+
return { path: 'lib/foo', namespace: 'mynamespace' }
2697+
})
2698+
build.onLoad({ filter: /foo/, namespace: 'mynamespace' }, () => {
2699+
return { contents: 'console.log("foo")' }
2700+
})
2701+
},
2702+
}],
2703+
})
2704+
2705+
assert.strictEqual(result.outputFiles.length, 2)
2706+
const map = result.outputFiles.find(file => file.path.endsWith('.js.map'))
2707+
const json = JSON.parse(map.text)
2708+
assert.deepStrictEqual(json.sources, ['mynamespace:lib/foo', '../entry.js'])
2709+
},
26782710
}
26792711

26802712
const makeRebuildUntilPlugin = () => {

0 commit comments

Comments
 (0)