browserify: Insertion of globals breaks sourcemaps
When a source file that already has a sourcemap (from a prior transform) is transformed to insert globals, the sourcemap is not updated, which breaks all positions in the file thereafter.
A trivial reproducing test case using coffeeify (this bug has nothing to do with coffeeify specifically; any transform that uses sourcemaps is affected):
x.coffee
global.foo = 3
console.log('hello')
command line
browserify -t coffeeify -d x.coffee
This link shows the resulting sourcemap. Note how the addition of the (function (global){ line causes the mappings to be off by exactly one line at that point. This offset will persist through the entire bundle, as the mappings are calculated relative to the original output rather than the transformed output.
About this issue
- Original URL
- State: open
- Created 10 years ago
- Comments: 16 (2 by maintainers)
A problem people still might be seeing (with source maps when global detection is not disabled and variables such as
globalare found (and withdebug: true), as well as the presence of a simple transform likeuglifyify) is the Windows-specific issue at https://github.com/thlorenz/combine-source-map/pull/23I’m adding further details below as a record (since it was little fun to debug!), but the PR already addresses the concern succinctly.
If the PR is still not accepted after my reminder, I think
browserifyought to depend on the PR’s fork ofcombine-source-map(orbrowserify’s own copy of it) to resolve this (via updates or forks ofinsert-module-globalsandbrowser-pack, the dependencies whichbrowserifydirectly includes and which both (problematically) utilize the unfixedcombine-source-map).I am attempting to use node-browserify with
uglifyifyto handle minification while preserving info about source files to source maps.(I’m also adding my own build of
mapstractionto save the map to an external file (while being able to deal with base and relative paths) though this latter plugin only does anything of substance after its stream ends and that only occurs after the problem mentioned below.)Since I did not add
detectGlobals: false,insert-module-globalswill be invoked. This creates athroughstream whoseendcalls a functioncloseOverwhich combines this stream’s chunks and invokescombine-source-map’screate(which just builds aCombiner) and then invokes theCombiner’saddFilewith these source contents, and in so doing gets its source converted into a map as such:var existingMap = resolveMap(opts.source);.The map then gets passed to
Combiner.prototype._addExistingMapwhich copies the mapvar mappings = mappingsFromMap(existingMap);wheremappingsFromMaprefers tolib/mappings-from-map.Later in
Combiner.prototype._addExistingMapthe following is called (though the code preceding it invokingthis.generator.addSourceContentis also affected because of its use ofrebaseRelativePath):In my case,
sourceFileistypes/errors.jswhilemapping.sourceiserrors.jsand when it is resolved, it becomestypes\errors.js, so that is the mapping that is added (with Windows backslashes).Later, when browserify continues its normal work unrelated to inserting globals, apparently since we have
debugenabled,Browserify.prototype._debuggets called, including with this line:Although a Windows-style path is present in
row.file(C:\<path to my repos>\typeson-registry\types\errors.js), the conversion to a relative path with the backslashes escaped leadsrow.sourceFileto getting a non-Windows pathtypes/errors.js. Therowis added to the stream and somehowbrowser-pack(which had been invoked earlier by browserify) gets itswritemethod invoked with this row and it then invokesaddFile(on the earlier created instance ofcombine-source-map) with an object including the non-Windowsrow.sourceFilepath.The above-mentioned
_addExistingMapmethod fromcombine-source-mapthus gets called again, callingaddSourceContent(andaddMappings) on an earlier createdinline-source-mapgenerator and to determine which path to supply (and determine what file if any ends up getting added).Before supplying the arguments, however,
_addExistingMapwill invokerebaseRelativePathto check whether the currently supplied file (the non-Windows one in this case) matches any of the previous existing ones (which it should since it has been added already albeit in Windows form).Since the code within
rebaseRelativePathofcombine-source-mapdoes a mere check without normalization ofif (sourceFile === relativeRootedPath ||, there is a failure to match due to the difference in slashes. This causes the problem that the following line,return path.join(path.dirname(sourceFile), relativeRootedPath);is run which effectively adds another directory onto the path (e.g., so my file,types/errors.jsmistakenly becomestypes/types/errors.jsin the source map).The PR details another issue whereby non-recognition can also occur because a file (e.g., from CoffeeScript or TypeScript) is not recognized with its converted extension.