From 8990c1738f7aab5eb5be5517975e90adba4dc6c3 Mon Sep 17 00:00:00 2001 From: Ferdinand Prantl Date: Mon, 3 Jan 2022 09:49:45 +0100 Subject: [PATCH 1/3] feat: Wire up source maps from transpiled modules to the bundle source map * Depend on source-map-url to detect and remove a source map. * Depend on source-map -resolve to extract and decode a source map. * Ensure a semicolon at the end of a single module in front of the inline source map. * If a plugin transpiles a script, do not add the transpiled script with the name ! to the source maps; add the original source under the original name. * Remove the code sections enclosed by excluding pragmas before the single module is appended to the output bundle to ensure proper offset for the line shifts. * Do not wrap single modules with extra leading and trailing line breaks. Put an extra line break between a pair of single modules when appending the to the output bundle. * If a single module contains an inline source map, apply it to the offsetting source map, when appending the module to the output bundle. --- build/jslib/build.js | 178 ++++++++++++--- build/jslib/source-map-resolve.js | 365 ++++++++++++++++++++++++++++++ build/jslib/source-map-url.js | 43 ++++ dist.js | 2 + 4 files changed, 558 insertions(+), 30 deletions(-) create mode 100644 build/jslib/source-map-resolve.js create mode 100644 build/jslib/source-map-url.js diff --git a/build/jslib/build.js b/build/jslib/build.js index 04c2c3d3..72d3da17 100644 --- a/build/jslib/build.js +++ b/build/jslib/build.js @@ -17,7 +17,11 @@ define(function (require) { requirePatch = require('requirePatch'), env = require('env'), commonJs = require('commonJs'), - SourceMapGenerator = require('source-map').SourceMapGenerator, + sourceMapExports = require('source-map'), + SourceMapGenerator = sourceMapExports.SourceMapGenerator, + SourceMapConsumer = sourceMapExports.SourceMapConsumer, + sourceMappingURL = require('source-map-url'), + sourceMapResolve = require('source-map-resolve'), hasProp = lang.hasProp, getOwn = lang.getOwn, falseProp = lang.falseProp, @@ -89,11 +93,26 @@ define(function (require) { * those cases. */ function addSemiColon(text, config) { + var lines, lineCount, lastCodeLine; if (config.skipSemiColonInsertion || endsWithSemiColonRegExp.test(text)) { return text; - } else { - return text + ";"; } + // If a source map is attached to the and of the script, ensure that + // the semicolon is added to the preceding line. + if (sourceMappingURL.existsIn(text)) { + lines = text.split("\n"); + lineCount = lines.length; + // Check if the source map is on the last line. + if (lines[lineCount - 1].indexOf("//# sourceMappingURL=") === 0) { + lastCodeLine = lines[lineCount - 2]; + if (endsWithSemiColonRegExp.test(lastCodeLine)) { + return text; + } + lines[lineCount - 2] = lastCodeLine + ";"; + return lines.join("\n"); + } + } + return text + ";"; } function endsWithSlash(dirName) { @@ -141,7 +160,8 @@ define(function (require) { * @returns {string} fileContents with singleContents appended */ function appendToFileContents(fileContents, singleContents, path, config, module, sourceMapGenerator) { - var refPath, sourceMapPath, resourcePath, pluginId, sourceMapLineNumber, lineCount, parts, i; + var refPath, sourceMapPath, resourcePath, pluginId, sourceMapLineNumber, lineCount, parts, i, + singleLines, /*encodingIndex,*/ singleSourceMap, singleSourceMapConsumer; if (sourceMapGenerator) { if (config.out) { refPath = config.baseUrl; @@ -162,34 +182,124 @@ define(function (require) { pluginId = parts.shift(); resourcePath = parts.join('!'); if (resourceIsModuleIdRegExp.test(resourcePath)) { + // Retain the original file name without appending !plugin, + // so that the source maps will not include both original and + // transpiled files, but only the original one. sourceMapPath = build.makeRelativeFilePath(refPath, require.toUrl(resourcePath)) + + // (config.transpiledSourceMapExtensions && + // config.transpiledSourceMapExtensions[pluginId] || '!' + pluginId); '!' + pluginId; } else { sourceMapPath = path; } } + // Separate modules in the bundle by one or two empty lines. + if (fileContents.length !== 0) { + fileContents += "\n\n"; + } + // Line offset to remap the single module in the bundle to. sourceMapLineNumber = fileContents.split('\n').length - 1; - lineCount = singleContents.split('\n').length; - for (i = 1; i <= lineCount; i += 1) { - sourceMapGenerator.addMapping({ - generated: { - line: sourceMapLineNumber + i, - column: 0 - }, - original: { - line: i, - column: 0 - }, - source: sourceMapPath + + // Remove the code that is omitted by pragmas when the bundle is saved. + // If left here, the source map line indexes would be skewed ahead. + singleContents = pragma.process(sourceMapPath, singleContents, config, 'OnSave'); + singleLines = singleContents.split('\n'); + lineCount = singleLines.length; + + // Extract the source map from the last line of the single module. + // if (singleLines[singleLines.length - 1].indexOf("//# sourceMappingURL=") === 0) { + // singleLastLine = singleLines.pop(); + // --lineCount; + // indexComma = singleLastLine.indexOf(","); + // if (indexComma > 0) { + // singleSourceMap = atob(singleLastLine.substr(indexComma + 1)); + // } + // singleContents = singleLines.join("\n"); + // } + singleSourceMap = sourceMapResolve.resolveSourceMapSync(singleContents, sourceMapPath, file.readFileSync); + // singleSourceMap = sourceMappingURL.getFrom(singleContents); + if (singleSourceMap) { + singleSourceMap = singleSourceMap.map; + // if (singleSourceMap.indexOf("data:") === 0) { + // const sourceMappingURLParts = /^data:([^,;]*)(?:;charset=([^,;]*))?(?:;([^,;]*))?(?:,(.*))?$/ + // encodingIndex = singleSourceMap.indexOf(";base64,") + // if (encodingIndex < 0) { + // } + // throw new Error("Source maps from http:// or https:// are not implemented yet."); + // singleSourceMap = atob(singleSourceMap.substr(encodingIndex + 8)); + // } else if (singleSourceMap.indexOf("http:") === 0 | singleSourceMap.indexOf("https:") === 0) { + // throw new Error("Source maps from http:// or https:// are not implemented yet."); + // } else { + // singleSourceMap = file.readFile(build.makeAbsPath(singleSourceMap, file.parent(sourceMapPath))); + // } + singleContents = sourceMappingURL.removeFrom(singleContents); + } + + // Merging the original source map using SourceMapGenerator.applySourceMap + // does not work if the built-in minificatoin by UglifyJS is enabled. + if (singleSourceMap && config.optimize !== 'uglify2') { + singleSourceMapConsumer = new SourceMapConsumer(singleSourceMap); + // Clone the mappings from the input source map shifted by the current + // line count of the target bundle. + singleSourceMapConsumer.eachMapping(function(mapping) { + // Sanity check for the mapping, which needs to point to a line within + // the single module and source + original location must not be null. + if (mapping.generatedLine <= lineCount && mapping.source) { + sourceMapGenerator.addMapping({ + generated: { + line: sourceMapLineNumber + mapping.generatedLine, + column: mapping.generatedColumn + }, + original: { + line: mapping.originalLine, + column: mapping.originalColumn + }, + source: mapping.source, + name: mapping.name + }); + } }); - } + // If there were more sources of the single module, transfer them + // to the source maps of the bundle. + singleSourceMapConsumer.sources.forEach(function (source) { + var content = singleSourceMapConsumer.sourceContentFor(source); + if (content) { + sourceMapGenerator.setSourceContent(source, content); + } + }); + } else { + // Add source mappings for the lines of the single module shifted + // by the current line count of the target bundle. + for (i = 1; i <= lineCount; i += 1) { + sourceMapGenerator.addMapping({ + generated: { + line: sourceMapLineNumber + i, + column: 0 + }, + original: { + line: i, + column: 0 + }, + source: sourceMapPath + }); + } - //Store the content of the original in the source - //map since other transforms later like minification - //can mess up translating back to the original - //source. - sourceMapGenerator.setSourceContent(sourceMapPath, singleContents); + // Store the content of the original in the source map since other + // transforms later like minification can mess up translating back + // to the original source. + sourceMapGenerator.setSourceContent(sourceMapPath, singleContents); + + // Adapt the source maps of the single module start from the original + // source code instead of from the single module inserted to the bundle. + if (singleSourceMap) { + // var sourceMapLog = SourceMapGenerator.fromSourceMap(new SourceMapConsumer(singleSourceMap)); + // console.log('Source map of', sourceMapPath + ':'); + // console.log(sourceMapLog.toJSON()); + singleSourceMapConsumer = new SourceMapConsumer(singleSourceMap); + sourceMapGenerator.applySourceMap(singleSourceMapConsumer, sourceMapPath); + } + } } fileContents += singleContents; return fileContents; @@ -1964,13 +2074,19 @@ define(function (require) { if (builder.write) { writeApi = function (input) { - singleContents += "\n" + addSemiColon(input, config); + // Do not prepend a line break here. If the input contained + // a source map, it would break it. Line breaks can be added + // when concatenating single modules to the output bundle. + singleContents += addSemiColon(input, config); if (config.onBuildWrite) { singleContents = config.onBuildWrite(moduleName, path, singleContents); } }; writeApi.asModule = function (moduleName, input) { - singleContents += "\n" + + // Do not prepend a line break here. If the input contained + // a source map, it would break it. Line breaks can be added + // when concatenating single modules to the output bundle. + singleContents += addSemiColon(build.toTransport(namespace, moduleName, path, input, layer, { useSourceUrl: layer.context.config.useSourceUrl }), config); @@ -2085,11 +2201,10 @@ define(function (require) { } } - //Add line break at end of file, instead of at beginning, - //so source map line numbers stay correct, but still allow - //for some space separation between files in case ASI issues - //for concatenation would cause an error otherwise. - singleContents += '\n'; + // Do not prepend a line break here. If the input contained + // a source map, it would break it. Line breaks can be added + // when concatenating single modules to the output bundle. + // singleContents += '\n'; //Add to the source map and to the final contents fileContents = appendToFileContents(fileContents, singleContents, path, config, module, @@ -2106,8 +2221,11 @@ define(function (require) { path = module._buildPath; } builder.onLayerEnd(function (input) { + // Do not prepend a line break here. If the input contained + // a source map, it would break it. Line breaks can be added + // when concatenating single modules to the output bundle. fileContents = - appendToFileContents(fileContents, "\n" + addSemiColon(input, config), + appendToFileContents(fileContents, addSemiColon(input, config), 'onLayerEnd' + index + '.js', config, module, sourceMapGenerator); }, { name: module.name, diff --git a/build/jslib/source-map-resolve.js b/build/jslib/source-map-resolve.js new file mode 100644 index 00000000..0bc387b4 --- /dev/null +++ b/build/jslib/source-map-resolve.js @@ -0,0 +1,365 @@ +// Copyright 2014-2020 Simon Lydell +define(function() { + var urlLib = require("url") + var pathLib = require("path") + + function resolveUrl(/* ...urls */) { + return Array.prototype.reduce.call(arguments, function(resolved, nextUrl) { + return urlLib.resolve(resolved, nextUrl) + }) + } + + function convertWindowsPath(aPath) { + return pathLib.sep === "\\" ? aPath.replace(/\\/g, "/").replace(/^[a-z]:\/?/i, "/") : aPath + } + + function customDecodeUriComponent(string) { + // `decodeURIComponent` turns `+` into ` `, but that's not wanted. + return decodeURIComponent(string.replace(/\+/g, "%2B")) + } + + function callbackAsync(callback, error, result) { + setImmediate(function() { callback(error, result) }) + } + + function parseMapToJSON(string, data) { + try { + return JSON.parse(string.replace(/^\)\]\}'/, "")) + } catch (error) { + error.sourceMapData = data + throw error + } + } + + function readSync(read, url, data) { + var readUrl = customDecodeUriComponent(url) + try { + return String(read(readUrl)) + } catch (error) { + error.sourceMapData = data + throw error + } + } + + var innerRegex = /[#@] sourceMappingURL=([^\s'"]*)/ + var sourceMappingURLRegex = RegExp( + "(?:" + + "/\\*" + + "(?:\\s*\r?\n(?://)?)?" + + "(?:" + innerRegex.source + ")" + + "\\s*" + + "\\*/" + + "|" + + "//(?:" + innerRegex.source + ")" + + ")" + + "\\s*" + ) + + function getSourceMappingUrl(code) { + var match = code.match(sourceMappingURLRegex) + return match ? match[1] || match[2] || "" : null + } + + function resolveSourceMap(code, codeUrl, read, callback) { + var mapData + try { + mapData = resolveSourceMapHelper(code, codeUrl) + } catch (error) { + return callbackAsync(callback, error) + } + if (!mapData || mapData.map) { + return callbackAsync(callback, null, mapData) + } + var readUrl = customDecodeUriComponent(mapData.url) + read(readUrl, function(error, result) { + if (error) { + error.sourceMapData = mapData + return callback(error) + } + mapData.map = String(result) + try { + mapData.map = parseMapToJSON(mapData.map, mapData) + } catch (error) { + return callback(error) + } + callback(null, mapData) + }) + } + + function resolveSourceMapSync(code, codeUrl, read) { + var mapData = resolveSourceMapHelper(code, codeUrl) + if (!mapData || mapData.map) { + return mapData + } + mapData.map = readSync(read, mapData.url, mapData) + mapData.map = parseMapToJSON(mapData.map, mapData) + return mapData + } + + var dataUriRegex = /^data:([^,;]*)(;[^,;]*)*(?:,(.*))?$/ + + /** + * The media type for JSON text is application/json. + * + * {@link https://tools.ietf.org/html/rfc8259#section-11 | IANA Considerations } + * + * `text/json` is non-standard media type + */ + var jsonMimeTypeRegex = /^(?:application|text)\/json$/ + + /** + * JSON text exchanged between systems that are not part of a closed ecosystem + * MUST be encoded using UTF-8. + * + * {@link https://tools.ietf.org/html/rfc8259#section-8.1 | Character Encoding} + */ + var jsonCharacterEncoding = "utf-8" + + function base64ToBuf(b64) { + var binStr = atob(b64) + var len = binStr.length + var arr = new Uint8Array(len) + for (var i = 0; i < len; i++) { + arr[i] = binStr.charCodeAt(i) + } + return arr + } + + function decodeBase64String(b64) { + if (typeof TextDecoder === "undefined" || typeof Uint8Array === "undefined") { + return atob(b64) + } + var buf = base64ToBuf(b64); + // Note: `decoder.decode` method will throw a `DOMException` with the + // `"EncodingError"` value when an coding error is found. + var decoder = new TextDecoder(jsonCharacterEncoding, {fatal: true}) + return decoder.decode(buf); + } + + function resolveSourceMapHelper(code, codeUrl) { + codeUrl = convertWindowsPath(codeUrl) + + var url = getSourceMappingUrl(code) + if (!url) { + return null + } + + var dataUri = url.match(dataUriRegex) + if (dataUri) { + var mimeType = dataUri[1] || "text/plain" + var lastParameter = dataUri[2] || "" + var encoded = dataUri[3] || "" + var data = { + sourceMappingURL: url, + url: null, + sourcesRelativeTo: codeUrl, + map: encoded + } + if (!jsonMimeTypeRegex.test(mimeType)) { + var error = new Error("Unuseful data uri mime type: " + mimeType) + error.sourceMapData = data + throw error + } + try { + data.map = parseMapToJSON( + lastParameter === ";base64" ? decodeBase64String(encoded) : decodeURIComponent(encoded), + data + ) + } catch (error) { + error.sourceMapData = data + throw error + } + return data + } + + var mapUrl = resolveUrl(codeUrl, url) + return { + sourceMappingURL: url, + url: mapUrl, + sourcesRelativeTo: mapUrl, + map: null + } + } + + function resolveSources(map, mapUrl, read, options, callback) { + if (typeof options === "function") { + callback = options + options = {} + } + var pending = map.sources ? map.sources.length : 0 + var result = { + sourcesResolved: [], + sourcesContent: [] + } + + if (pending === 0) { + callbackAsync(callback, null, result) + return + } + + var done = function() { + pending-- + if (pending === 0) { + callback(null, result) + } + } + + resolveSourcesHelper(map, mapUrl, options, function(fullUrl, sourceContent, index) { + result.sourcesResolved[index] = fullUrl + if (typeof sourceContent === "string") { + result.sourcesContent[index] = sourceContent + callbackAsync(done, null) + } else { + var readUrl = customDecodeUriComponent(fullUrl) + read(readUrl, function(error, source) { + result.sourcesContent[index] = error ? error : String(source) + done() + }) + } + }) + } + + function resolveSourcesSync(map, mapUrl, read, options) { + var result = { + sourcesResolved: [], + sourcesContent: [] + } + + if (!map.sources || map.sources.length === 0) { + return result + } + + resolveSourcesHelper(map, mapUrl, options, function(fullUrl, sourceContent, index) { + result.sourcesResolved[index] = fullUrl + if (read !== null) { + if (typeof sourceContent === "string") { + result.sourcesContent[index] = sourceContent + } else { + var readUrl = customDecodeUriComponent(fullUrl) + try { + result.sourcesContent[index] = String(read(readUrl)) + } catch (error) { + result.sourcesContent[index] = error + } + } + } + }) + + return result + } + + var endingSlash = /\/?$/ + + function resolveSourcesHelper(map, mapUrl, options, fn) { + options = options || {} + mapUrl = convertWindowsPath(mapUrl) + var fullUrl + var sourceContent + var sourceRoot + for (var index = 0, len = map.sources.length; index < len; index++) { + sourceRoot = null + if (typeof options.sourceRoot === "string") { + sourceRoot = options.sourceRoot + } else if (typeof map.sourceRoot === "string" && options.sourceRoot !== false) { + sourceRoot = map.sourceRoot + } + // If the sourceRoot is the empty string, it is equivalent to not setting + // the property at all. + if (sourceRoot === null || sourceRoot === '') { + fullUrl = resolveUrl(mapUrl, map.sources[index]) + } else { + // Make sure that the sourceRoot ends with a slash, so that `/scripts/subdir` becomes + // `/scripts/subdir/`, not `/scripts/`. Pointing to a file as source root + // does not make sense. + fullUrl = resolveUrl(mapUrl, sourceRoot.replace(endingSlash, "/"), map.sources[index]) + } + sourceContent = (map.sourcesContent || [])[index] + fn(fullUrl, sourceContent, index) + } + } + + function resolve(code, codeUrl, read, options, callback) { + if (typeof options === "function") { + callback = options + options = {} + } + if (code === null) { + var mapUrl = codeUrl + var data = { + sourceMappingURL: null, + url: mapUrl, + sourcesRelativeTo: mapUrl, + map: null + } + var readUrl = customDecodeUriComponent(mapUrl) + read(readUrl, function(error, result) { + if (error) { + error.sourceMapData = data + return callback(error) + } + data.map = String(result) + try { + data.map = parseMapToJSON(data.map, data) + } catch (error) { + return callback(error) + } + _resolveSources(data) + }) + } else { + resolveSourceMap(code, codeUrl, read, function(error, mapData) { + if (error) { + return callback(error) + } + if (!mapData) { + return callback(null, null) + } + _resolveSources(mapData) + }) + } + + function _resolveSources(mapData) { + resolveSources(mapData.map, mapData.sourcesRelativeTo, read, options, function(error, result) { + if (error) { + return callback(error) + } + mapData.sourcesResolved = result.sourcesResolved + mapData.sourcesContent = result.sourcesContent + callback(null, mapData) + }) + } + } + + function resolveSync(code, codeUrl, read, options) { + var mapData + if (code === null) { + var mapUrl = codeUrl + mapData = { + sourceMappingURL: null, + url: mapUrl, + sourcesRelativeTo: mapUrl, + map: null + } + mapData.map = readSync(read, mapUrl, mapData) + mapData.map = parseMapToJSON(mapData.map, mapData) + } else { + mapData = resolveSourceMapSync(code, codeUrl, read) + if (!mapData) { + return null + } + } + var result = resolveSourcesSync(mapData.map, mapData.sourcesRelativeTo, read, options) + mapData.sourcesResolved = result.sourcesResolved + mapData.sourcesContent = result.sourcesContent + return mapData + } + + return { + resolveSourceMap: resolveSourceMap, + resolveSourceMapSync: resolveSourceMapSync, + resolveSources: resolveSources, + resolveSourcesSync: resolveSourcesSync, + resolve: resolve, + resolveSync: resolveSync, + parseMapToJSON: parseMapToJSON + } +}); diff --git a/build/jslib/source-map-url.js b/build/jslib/source-map-url.js new file mode 100644 index 00000000..ef0b24d8 --- /dev/null +++ b/build/jslib/source-map-url.js @@ -0,0 +1,43 @@ +// Copyright 2014 Simon Lydell +define(function() { + var innerRegex = /[#@] sourceMappingURL=([^\s'"]*)/ + var regex = RegExp( + "(?:" + + "/\\*" + + "(?:\\s*\r?\n(?://)?)?" + + "(?:" + innerRegex.source + ")" + + "\\s*" + + "\\*/" + + "|" + + "//(?:" + innerRegex.source + ")" + + ")" + + "\\s*" + ) + + return { + regex: regex, + _innerRegex: innerRegex, + + getFrom: function(code) { + var match = code.match(regex) + return (match ? match[1] || match[2] || "" : null) + }, + + existsIn: function(code) { + return regex.test(code) + }, + + removeFrom: function(code) { + return code.replace(regex, "") + }, + + insertBefore: function(code, string) { + var match = code.match(regex) + if (match) { + return code.slice(0, match.index) + string + code.slice(match.index) + } else { + return code + string + } + } + } +}); diff --git a/dist.js b/dist.js index 70e06a23..e2427834 100644 --- a/dist.js +++ b/dist.js @@ -38,6 +38,8 @@ var fs = require('fs'), 'build/jslib/esprima.js', 'build/jslib/esprimaAdapter.js', 'build/jslib/source-map.js', + 'build/jslib/source-map-url.js', + 'build/jslib/source-map-resolve.js', 'build/jslib/uglifyjs.js', 'build/jslib/parse.js', 'build/jslib/transform.js', From a7bebf3167394c0f58dde9a3c3b22958ecab417a Mon Sep 17 00:00:00 2001 From: Ferdinand Prantl Date: Sun, 9 Jan 2022 01:23:42 +0100 Subject: [PATCH 2/3] fix: Log errors from source map parsing, unify sourcer map wiring up Use one code for wiring up source maps from uglified and not uglified modules. --- build/jslib/build.js | 54 ++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/build/jslib/build.js b/build/jslib/build.js index 72d3da17..f28c2727 100644 --- a/build/jslib/build.js +++ b/build/jslib/build.js @@ -217,7 +217,12 @@ define(function (require) { // } // singleContents = singleLines.join("\n"); // } - singleSourceMap = sourceMapResolve.resolveSourceMapSync(singleContents, sourceMapPath, file.readFileSync); + try { + singleSourceMap = sourceMapResolve.resolveSourceMapSync(singleContents, sourceMapPath, file.readFileSync); + } catch (error) { + console.log('Resolving source maps for "' + sourceMapPath + '" failed:'); + console.log(error); + } // singleSourceMap = sourceMappingURL.getFrom(singleContents); if (singleSourceMap) { singleSourceMap = singleSourceMap.map; @@ -238,34 +243,35 @@ define(function (require) { // Merging the original source map using SourceMapGenerator.applySourceMap // does not work if the built-in minificatoin by UglifyJS is enabled. - if (singleSourceMap && config.optimize !== 'uglify2') { + if (singleSourceMap) { singleSourceMapConsumer = new SourceMapConsumer(singleSourceMap); // Clone the mappings from the input source map shifted by the current // line count of the target bundle. - singleSourceMapConsumer.eachMapping(function(mapping) { - // Sanity check for the mapping, which needs to point to a line within - // the single module and source + original location must not be null. - if (mapping.generatedLine <= lineCount && mapping.source) { - sourceMapGenerator.addMapping({ - generated: { - line: sourceMapLineNumber + mapping.generatedLine, - column: mapping.generatedColumn - }, - original: { - line: mapping.originalLine, - column: mapping.originalColumn - }, - source: mapping.source, - name: mapping.name - }); + singleSourceMapConsumer.eachMapping(function (mapping) { + var newMapping = { + generated: { + line: sourceMapLineNumber + mapping.generatedLine, + column: mapping.generatedColumn + } + }; + if (mapping.source != null) { + newMapping.source = mapping.source; + newMapping.original = { + line: mapping.originalLine, + column: mapping.originalColumn + }; + if (mapping.name != null) { + newMapping.name = mapping.name; + } } + sourceMapGenerator.addMapping(newMapping); }); // If there were more sources of the single module, transfer them // to the source maps of the bundle. singleSourceMapConsumer.sources.forEach(function (source) { var content = singleSourceMapConsumer.sourceContentFor(source); if (content) { - sourceMapGenerator.setSourceContent(source, content); + sourceMapGenerator.setSourceContent(source, content); } }); } else { @@ -289,16 +295,6 @@ define(function (require) { // transforms later like minification can mess up translating back // to the original source. sourceMapGenerator.setSourceContent(sourceMapPath, singleContents); - - // Adapt the source maps of the single module start from the original - // source code instead of from the single module inserted to the bundle. - if (singleSourceMap) { - // var sourceMapLog = SourceMapGenerator.fromSourceMap(new SourceMapConsumer(singleSourceMap)); - // console.log('Source map of', sourceMapPath + ':'); - // console.log(sourceMapLog.toJSON()); - singleSourceMapConsumer = new SourceMapConsumer(singleSourceMap); - sourceMapGenerator.applySourceMap(singleSourceMapConsumer, sourceMapPath); - } } } fileContents += singleContents; From 8e4b0983cc49888d140f544fed7b9dc81a848ae1 Mon Sep 17 00:00:00 2001 From: Ferdinand Prantl Date: Fri, 11 Feb 2022 08:17:40 +0100 Subject: [PATCH 3/3] fix: Fix loading of source maps from an external file * Use an absolute path instead of a path relative to baseUrl. The source map package understands the relative paths relative to the process current directory. * The name of the synchronous file-reading method in r.js file system facade is readFile. --- build/jslib/build.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/jslib/build.js b/build/jslib/build.js index f28c2727..0cb6f1c1 100644 --- a/build/jslib/build.js +++ b/build/jslib/build.js @@ -218,7 +218,7 @@ define(function (require) { // singleContents = singleLines.join("\n"); // } try { - singleSourceMap = sourceMapResolve.resolveSourceMapSync(singleContents, sourceMapPath, file.readFileSync); + singleSourceMap = sourceMapResolve.resolveSourceMapSync(singleContents, path, file.readFile); } catch (error) { console.log('Resolving source maps for "' + sourceMapPath + '" failed:'); console.log(error);