support optional output of names in source maps (#3784)

This commit is contained in:
Alex Lam S.L
2020-04-17 00:20:48 +01:00
committed by GitHub
parent 0ce71bbec0
commit 83f42ede36
5 changed files with 115 additions and 27 deletions

View File

@@ -126,6 +126,7 @@ a double dash to prevent input files being used as option arguments:
`includeSources` Pass this flag if you want to include `includeSources` Pass this flag if you want to include
the content of source files in the the content of source files in the
source map as sourcesContent property. source map as sourcesContent property.
`names` Include symbol names in the source map.
`root` Path to the original source to be included in `root` Path to the original source to be included in
the source map. the source map.
`url` If specified, path to the source map to append in `url` If specified, path to the source map to append in
@@ -159,6 +160,9 @@ Additional options:
- `--source-map "root='<URL>'"` to pass the URL where the original files can be found. - `--source-map "root='<URL>'"` to pass the URL where the original files can be found.
- `--source-map "names=false"` to omit symbol names if you want to reduce size
of the source map file.
- `--source-map "url='<URL>'"` to specify the URL where the source map can be found. - `--source-map "url='<URL>'"` to specify the URL where the source map can be found.
Otherwise UglifyJS assumes HTTP `X-SourceMap` is being used and will omit the Otherwise UglifyJS assumes HTTP `X-SourceMap` is being used and will omit the
`//# sourceMappingURL=` directive. `//# sourceMappingURL=` directive.
@@ -593,6 +597,9 @@ var result = UglifyJS.minify({"compiled.js": "compiled code"}, {
If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.url`. If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.url`.
If you wish to reduce file size of the source map, set option `sourceMap.names`
to be `false` and all symbol names will be omitted.
## Parse options ## Parse options
- `bare_returns` (default `false`) -- support top level `return` statements - `bare_returns` (default `false`) -- support top level `return` statements

View File

@@ -129,6 +129,7 @@ function minify(files, options) {
content: null, content: null,
filename: null, filename: null,
includeSources: false, includeSources: false,
names: true,
root: null, root: null,
url: null, url: null,
}, true); }, true);
@@ -138,7 +139,7 @@ function minify(files, options) {
warnings.push(warning); warnings.push(warning);
}, options.warnings == "verbose"); }, options.warnings == "verbose");
if (timings) timings.parse = Date.now(); if (timings) timings.parse = Date.now();
var source_maps, toplevel; var toplevel;
if (files instanceof AST_Toplevel) { if (files instanceof AST_Toplevel) {
toplevel = files; toplevel = files;
} else { } else {
@@ -151,19 +152,17 @@ function minify(files, options) {
if (typeof source_map_content == "string" && source_map_content != "inline") { if (typeof source_map_content == "string" && source_map_content != "inline") {
source_map_content = parse_source_map(source_map_content); source_map_content = parse_source_map(source_map_content);
} }
source_maps = source_map_content && Object.create(null); if (source_map_content) options.sourceMap.orig = Object.create(null);
for (var name in files) if (HOP(files, name)) { for (var name in files) if (HOP(files, name)) {
options.parse.filename = name; options.parse.filename = name;
options.parse.toplevel = toplevel = parse(files[name], options.parse); options.parse.toplevel = toplevel = parse(files[name], options.parse);
if (source_maps) { if (source_map_content == "inline") {
if (source_map_content == "inline") { var inlined_content = read_source_map(name, toplevel);
var inlined_content = read_source_map(name, toplevel); if (inlined_content) {
if (inlined_content) { options.sourceMap.orig[name] = parse_source_map(inlined_content);
source_maps[name] = parse_source_map(inlined_content);
}
} else {
source_maps[name] = source_map_content;
} }
} else if (source_map_content) {
options.sourceMap.orig[name] = source_map_content;
} }
} }
} }
@@ -202,12 +201,7 @@ function minify(files, options) {
} }
if (!HOP(options.output, "code") || options.output.code) { if (!HOP(options.output, "code") || options.output.code) {
if (options.sourceMap) { if (options.sourceMap) {
options.output.source_map = SourceMap({ options.output.source_map = SourceMap(options.sourceMap);
content: options.sourceMap.includeSources,
file: options.sourceMap.filename,
orig: source_maps,
root: options.sourceMap.root
});
if (options.sourceMap.includeSources) { if (options.sourceMap.includeSources) {
if (files instanceof AST_Toplevel) { if (files instanceof AST_Toplevel) {
throw new Error("original source content unavailable"); throw new Error("original source content unavailable");

View File

@@ -90,14 +90,8 @@ function create_array_map() {
} }
function SourceMap(options) { function SourceMap(options) {
options = defaults(options, {
content: false,
file: null,
root: null,
orig: null,
}, true);
var sources = create_array_map(); var sources = create_array_map();
var sources_content = options.content && Object.create(null); var sources_content = options.includeSources && Object.create(null);
var names = create_array_map(); var names = create_array_map();
var mappings = ""; var mappings = "";
if (options.orig) Object.keys(options.orig).forEach(function(name) { if (options.orig) Object.keys(options.orig).forEach(function(name) {
@@ -155,7 +149,7 @@ function SourceMap(options) {
toString: function() { toString: function() {
return JSON.stringify({ return JSON.stringify({
version: 3, version: 3,
file: options.file || undefined, file: options.filename || undefined,
sourceRoot: options.root || undefined, sourceRoot: options.root || undefined,
sources: sources, sources: sources,
sourcesContent: sources_content ? sources.map(function(source) { sourcesContent: sources_content ? sources.map(function(source) {
@@ -188,7 +182,7 @@ function SourceMap(options) {
original_line = orig_line; original_line = orig_line;
mappings += vlq_encode(orig_col - original_column); mappings += vlq_encode(orig_col - original_column);
original_column = orig_col; original_column = orig_col;
if (name != null) { if (options.names && name != null) {
var name_idx = names.index(name); var name_idx = names.index(name);
mappings += vlq_encode(name_idx - name_index); mappings += vlq_encode(name_idx - name_index);
name_index = name_idx; name_index = name_idx;

View File

@@ -2,6 +2,7 @@ var assert = require("assert");
var exec = require("child_process").exec; var exec = require("child_process").exec;
var fs = require("fs"); var fs = require("fs");
var run_code = require("../sandbox").run_code; var run_code = require("../sandbox").run_code;
var to_ascii = require("../node").to_ascii;
function read(path) { function read(path) {
return fs.readFileSync(path, "utf8"); return fs.readFileSync(path, "utf8");
@@ -48,6 +49,62 @@ describe("bin/uglifyjs", function() {
done(); done();
}); });
}); });
it("Should work with --source-map names=true", function(done) {
exec([
uglifyjscmd,
"--beautify",
"--source-map", [
"names=true",
"url=inline",
].join(","),
].join(" "), function(err, stdout) {
if (err) throw err;
var expected = [
"var obj = {",
" p: a,",
" q: b",
"};",
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,",
].join("\n")
assert.strictEqual(stdout.slice(0, expected.length), expected);
var map = JSON.parse(to_ascii(stdout.slice(expected.length).trim()));
assert.deepEqual(map.names, [ "obj", "p", "a", "q", "b" ]);
done();
}).stdin.end([
"var obj = {",
" p: a,",
" q: b",
"};",
].join("\n"));
});
it("Should work with --source-map names=false", function(done) {
exec([
uglifyjscmd,
"--beautify",
"--source-map", [
"names=false",
"url=inline",
].join(","),
].join(" "), function(err, stdout) {
if (err) throw err;
var expected = [
"var obj = {",
" p: a,",
" q: b",
"};",
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,",
].join("\n")
assert.strictEqual(stdout.slice(0, expected.length), expected);
var map = JSON.parse(to_ascii(stdout.slice(expected.length).trim()));
assert.deepEqual(map.names, []);
done();
}).stdin.end([
"var obj = {",
" p: a,",
" q: b",
"};",
].join("\n"));
});
it("Should give sensible error against invalid input source map", function(done) { it("Should give sensible error against invalid input source map", function(done) {
var command = uglifyjscmd + " test/mocha.js --source-map content=blah,url=inline --verbose"; var command = uglifyjscmd + " test/mocha.js --source-map content=blah,url=inline --verbose";
exec(command, function(err, stdout, stderr) { exec(command, function(err, stdout, stderr) {

View File

@@ -7,11 +7,13 @@ function read(path) {
} }
function source_map(code) { function source_map(code) {
return JSON.parse(UglifyJS.minify(code, { var result = UglifyJS.minify(code, {
compress: false, compress: false,
mangle: false, mangle: false,
sourceMap: true, sourceMap: true,
}).map); });
if (result.error) throw result.error;
return JSON.parse(result.map);
} }
function get_map() { function get_map() {
@@ -65,6 +67,40 @@ describe("sourcemaps", function() {
].join("\n")); ].join("\n"));
assert.deepEqual(map.names, [ "enabled", "x" ]); assert.deepEqual(map.names, [ "enabled", "x" ]);
}); });
it("Should work with sourceMap.names=true", function() {
var result = UglifyJS.minify([
"var obj = {",
" p: a,",
" q: b",
"};",
].join("\n"), {
compress: false,
mangle: false,
sourceMap: {
names: true,
},
});
if (result.error) throw result.error;
var map = JSON.parse(result.map);
assert.deepEqual(map.names, [ "obj", "p", "a", "q", "b" ]);
});
it("Should work with sourceMap.names=false", function() {
var result = UglifyJS.minify([
"var obj = {",
" p: a,",
" q: b",
"};",
].join("\n"), {
compress: false,
mangle: false,
sourceMap: {
names: false,
},
});
if (result.error) throw result.error;
var map = JSON.parse(result.map);
assert.deepEqual(map.names, []);
});
it("Should mark array/object literals", function() { it("Should mark array/object literals", function() {
var result = UglifyJS.minify([ var result = UglifyJS.minify([
"var obj = {};", "var obj = {};",