Skip to content

Commit

Permalink
fix #899: cross-chunk import paths
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Mar 1, 2021
1 parent c1bec9b commit 4e1f535
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 0 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@
}
```

* Fix cross-chunk import paths ([#899](https://github.com/evanw/esbuild/issues/899))

This release fixes an issue with the `--chunk-names=` feature where import paths in between two different automatically-generated code splitting chunks were relative to the output directory instead of relative to the importing chunk. This caused an import failure with the imported chunk if the chunk names setting was configured to put the chunks into a subdirectory. This bug has been fixed.

## 0.8.53

* Support chunk and asset file name templates ([#733](https://github.com/evanw/esbuild/issues/733), [#888](https://github.com/evanw/esbuild/issues/888))
Expand Down
15 changes: 15 additions & 0 deletions internal/bundler/linker.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ type linkerContext struct {
files []file
hasErrors bool

// This is the relative path for automatically-generated code splitting chunks
// relative to the output directory
generatedChunkRelDir string

// This helps avoid an infinite loop when matching imports to exports
cycleDetector []importTracker

Expand Down Expand Up @@ -349,6 +353,15 @@ func newLinkerContext(
symbols: js_ast.NewSymbolMap(len(files)),
reachableFiles: reachableFiles,
dataForSourceMaps: dataForSourceMaps,

// Note: This contains placeholders instead of what the placeholders are
// substituted with. That should be fine though because this should only
// ever be used for figuring out how many "../" to add to a relative path
// from a chunk whose final path hasn't been calculated yet to a chunk
// whose final path has already been calculated. That and placeholders are
// never substituted with something containing a "/" so substitution should
// never change the "../" count.
generatedChunkRelDir: fs.Dir(config.TemplateToString(options.ChunkPathTemplate)),
}

// Clone various things since we may mutate them later
Expand Down Expand Up @@ -2755,6 +2768,7 @@ func (c *linkerContext) computeChunks() []chunkInfo {
if !ok {
chunk.entryBits = partMeta.entryBits
chunk.filesWithPartsInChunk = make(map[uint32]bool)
chunk.relDir = c.generatedChunkRelDir
chunk.chunkRepr = &chunkReprJS{}
chunks[key] = chunk
}
Expand All @@ -2771,6 +2785,7 @@ func (c *linkerContext) computeChunks() []chunkInfo {
if !ok {
chunk.entryBits = file.entryBits
chunk.filesWithPartsInChunk = make(map[uint32]bool)
chunk.relDir = c.generatedChunkRelDir
chunk.chunkRepr = &chunkReprJS{}
chunks[key] = chunk
}
Expand Down
64 changes: 64 additions & 0 deletions scripts/js-api-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -1282,6 +1282,70 @@ export {
assert.strictEqual(value.outputFiles[2].path, path.join(outdir, chunk))
},

async splittingWithChunkPathAndCrossChunkImportsIssue899({ esbuild, testDir }) {
const entry1 = path.join(testDir, 'src', 'entry1.js')
const entry2 = path.join(testDir, 'src', 'entry2.js')
const entry3 = path.join(testDir, 'src', 'entry3.js')
const shared1 = path.join(testDir, 'src', 'shared1.js')
const shared2 = path.join(testDir, 'src', 'shared2.js')
const shared3 = path.join(testDir, 'src', 'shared3.js')
await mkdirAsync(path.join(testDir, 'src')).catch(x => x)
await writeFileAsync(entry1, `
import { shared1 } from './shared1';
import { shared2 } from './shared2';
export default async function() {
return shared1() + shared2();
}
`)
await writeFileAsync(entry2, `
import { shared2 } from './shared2';
import { shared3 } from './shared3';
export default async function() {
return shared2() + shared3();
}
`)
await writeFileAsync(entry3, `
import { shared3 } from './shared3';
import { shared1 } from './shared1';
export default async function() {
return shared3() + shared1();
}
`)
await writeFileAsync(shared1, `
import { shared2 } from './shared2';
export function shared1() {
return shared2().replace('2', '1');
}
`)
await writeFileAsync(shared2, `
import { shared3 } from './shared3'
export function shared2() {
return 'shared2';
}
`)
await writeFileAsync(shared3, `
export function shared3() {
return 'shared3';
}
`)
const outdir = path.join(testDir, 'out')
await esbuild.build({
entryPoints: [entry1, entry2, entry3],
bundle: true,
outdir,
format: 'esm',
splitting: true,
outExtension: { '.js': '.mjs' },
chunkNames: 'chunks/[hash]/[name]',
})
const result1 = await import(path.join(outdir, 'entry1.mjs'))
const result2 = await import(path.join(outdir, 'entry2.mjs'))
const result3 = await import(path.join(outdir, 'entry3.mjs'))
assert.strictEqual(await result1.default(), 'shared1shared2');
assert.strictEqual(await result2.default(), 'shared2shared3');
assert.strictEqual(await result3.default(), 'shared3shared1');
},

async stdinStdoutBundle({ esbuild, testDir }) {
const auxiliary = path.join(testDir, 'auxiliary.js')
await writeFileAsync(auxiliary, 'export default 123')
Expand Down

0 comments on commit 4e1f535

Please sign in to comment.