From 4fefb145a0387346a62860e98f361826de1c2898 Mon Sep 17 00:00:00 2001 From: Evan Wallace Date: Tue, 5 Jan 2021 21:54:58 -0800 Subject: [PATCH] increment "nextSourcesIndex" correctly (#638) --- CHANGELOG.md | 4 ++++ internal/bundler/linker.go | 3 ++- scripts/package-lock.json | 32 ++++++++++++++++++++++++++++++++ scripts/package.json | 2 ++ scripts/verify-source-map.js | 25 ++++++++++++++++++++++++- 5 files changed, 64 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2010baa2cc8..1fb268b5f9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,10 @@ * Minification now takes advantage of the left-associativity of certain operators. This means `a && (b && c)` turns into `a && b && c`. +* Fix issues with source maps ([#638][https://github.com/evanw/esbuild/issues/638]) + + * Generated source maps were incorrect when an input file had a nested source map (i.e. contained a valid `//# sourceMappingURL=` comment) and the input source map had more than one source file. This regression was introduced by an optimization in version 0.8.25 that parallelizes the generation of certain internal source map data structures. The index into the generated `sources` array was incorrectly incremented by 1 for every input file instead of by the number of sources in the input source map. This issue has been fixed and now has test coverage. + ## 0.8.29 * Allow entry points outside of the `outbase` directory ([#634](https://github.com/evanw/esbuild/issues/634)) diff --git a/internal/bundler/linker.go b/internal/bundler/linker.go index 869ff5de334..4479773252f 100644 --- a/internal/bundler/linker.go +++ b/internal/bundler/linker.go @@ -4291,7 +4291,6 @@ func (c *linkerContext) generateSourceMapForChunk( continue } sourceIndexToSourcesIndex[result.sourceIndex] = nextSourcesIndex - nextSourcesIndex++ file := &c.files[result.sourceIndex] // Simple case: no nested source map @@ -4305,6 +4304,7 @@ func (c *linkerContext) generateSourceMapForChunk( prettyPath: file.source.PrettyPath, quotedContents: quotedContents, }) + nextSourcesIndex++ continue } @@ -4332,6 +4332,7 @@ func (c *linkerContext) generateSourceMapForChunk( quotedContents: quotedContents, }) } + nextSourcesIndex += len(sm.Sources) } // Write the sources diff --git a/scripts/package-lock.json b/scripts/package-lock.json index a2da19d9883..b0003f6419a 100644 --- a/scripts/package-lock.json +++ b/scripts/package-lock.json @@ -44,6 +44,11 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, + "fuse.js": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-3.2.0.tgz", + "integrity": "sha1-8ESOgGmFW/Kj5oPNwdMg5+KgfvQ=" + }, "glob": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", @@ -71,6 +76,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, "js-yaml": { "version": "3.14.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", @@ -80,6 +90,14 @@ "esprima": "^4.0.0" } }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -88,6 +106,11 @@ "brace-expansion": "^1.1.7" } }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -101,6 +124,15 @@ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, + "react": { + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/react/-/react-17.0.1.tgz", + "integrity": "sha512-lG9c9UuMHdcAexXtigOZLX8exLWkW0Ku29qPRU8uhF2R9BN96dLCt0psvzPLlHc5OWkgymP3qwTRgbnw5BKx3w==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", diff --git a/scripts/package.json b/scripts/package.json index 4e6dc889d4c..731a68b0ca9 100644 --- a/scripts/package.json +++ b/scripts/package.json @@ -1,7 +1,9 @@ { "dependencies": { "@types/node": "14.14.6", + "fuse.js": "3.2.0", "js-yaml": "3.14.0", + "react": "17.0.1", "rimraf": "3.0.2", "source-map": "0.7.3", "typescript": "4.0.5", diff --git a/scripts/verify-source-map.js b/scripts/verify-source-map.js index d9aea7595d1..3168a250af6 100644 --- a/scripts/verify-source-map.js +++ b/scripts/verify-source-map.js @@ -229,6 +229,23 @@ const toSearchPartialMappings = { entry: 'entry.js', } +const testCaseComplex = { + // "fuse.js" is included because it has a nested source map of some complexity. + // "react" is included after that because it's a big blob of code and helps + // make sure stuff after a nested source map works ok. + 'entry.js': ` + import Fuse from 'fuse.js' + import * as React from 'react' + console.log(Fuse, React) + `, +} + +const toSearchComplex = { + 'Score average:': '../../node_modules/fuse.js/dist/webpack:/src/index.js', + '0123456789': '../../node_modules/object-assign/index.js', + 'forceUpdate': '../../node_modules/react/cjs/react.production.min.js', +}; + async function check(kind, testCase, toSearch, { flags, entryPoints, crlf }) { let failed = 0 @@ -297,7 +314,8 @@ async function check(kind, testCase, toSearch, { flags, entryPoints, crlf }) { recordCheck(source === inSource, `expected: ${inSource} observed: ${source}`) const inJs = map.sourceContentFor(source) - const inIndex = inJs.indexOf(`"${id}"`) + let inIndex = inJs.indexOf(`"${id}"`) + if (inIndex < 0) inIndex = inJs.indexOf(`'${id}'`) if (inIndex < 0) throw new Error(`Failed to find "${id}" in input`) const inLines = inJs.slice(0, inIndex).split('\n') const inLine = inLines.length @@ -431,6 +449,11 @@ async function main() { entryPoints: ['a.js'], crlf, }), + check('complex' + suffix, testCaseComplex, toSearchComplex, { + flags: flags.concat('--outfile=out.js', '--bundle', '--define:process.env.NODE_ENV="production"'), + entryPoints: ['entry.js'], + crlf, + }), ) } }