From d8d494cd862c68e819163d208dfd8d792c5789c0 Mon Sep 17 00:00:00 2001 From: Greg Magolan Date: Tue, 8 Oct 2019 14:21:54 -0700 Subject: [PATCH] feat(terser): support .map files in directory inputs --- packages/terser/src/index.js | 22 ++++++++++---- packages/terser/test/BUILD.bazel | 5 +++- packages/terser/test/directory-args.spec.js | 29 +++++++++++++++---- .../terser/test/directory_input/BUILD.bazel | 3 +- packages/terser/test/sourcemap/BUILD.bazel | 25 ++++++++++++++++ .../terser/test/sourcemap/directory_spec.js | 27 +++++++++++++++++ .../rule.bzl => tools/declare_directory.bzl | 0 7 files changed, 96 insertions(+), 15 deletions(-) create mode 100644 packages/terser/test/sourcemap/directory_spec.js rename packages/terser/test/directory_input/rule.bzl => tools/declare_directory.bzl (100%) diff --git a/packages/terser/src/index.js b/packages/terser/src/index.js index 0407eae78b..26cba157ff 100644 --- a/packages/terser/src/index.js +++ b/packages/terser/src/index.js @@ -29,19 +29,27 @@ function isDirectory(input) { /** * Replaces directory url with the outputFile name in the url option of source-map argument */ -function directoryArgs(residualArgs, outputFile) { +function directoryArgs(residualArgs, inputFile, outputFile) { const sourceMapIndex = residualArgs.indexOf('--source-map'); if (sourceMapIndex === -1) { return residualArgs; } - const sourceMapOptions = residualArgs[sourceMapIndex + 1].split(','); - const newSourceMapOptions = sourceMapOptions.map( + // set the correct sourcemap url for this output file + let sourceMapOptions = residualArgs[sourceMapIndex + 1].split(',').map( o => o.startsWith('url=') ? `url='${path.basename(outputFile)}.map'` : o); + // if an input .map file exists then set the correct sourcemap content option + if (fs.existsSync(`${inputFile}.map`)) { + // even on Windows terser expects '/' path separators so we normalize these in the sourcemap + // content file path below + sourceMapOptions = sourceMapOptions.map( + o => o.startsWith('content=') ? `content='${inputFile.replace(/\\/g, '/')}.map'` : o); + } + return [ ...residualArgs.slice(0, sourceMapIndex + 1), - newSourceMapOptions.join(','), + sourceMapOptions.join(','), ...residualArgs.slice(sourceMapIndex + 2), ]; } @@ -59,8 +67,10 @@ function terserDirectory(input, output, residual, terserBinary) { function exec([inputFile, outputFile]) { active++; - let args = - [terserBinary, inputFile, '--output', outputFile, ...directoryArgs(residual, outputFile)]; + let args = [ + terserBinary, inputFile, '--output', outputFile, + ...directoryArgs(residual, inputFile, outputFile) + ]; spawn(process.execPath, args) .then( diff --git a/packages/terser/test/BUILD.bazel b/packages/terser/test/BUILD.bazel index 159d07169b..9300894b72 100644 --- a/packages/terser/test/BUILD.bazel +++ b/packages/terser/test/BUILD.bazel @@ -3,5 +3,8 @@ load("@npm_bazel_jasmine//:index.from_src.bzl", "jasmine_node_test") jasmine_node_test( name = "test", srcs = ["directory-args.spec.js"], - deps = ["@npm_bazel_terser//:index.js"], + deps = [ + "@npm//tmp", + "@npm_bazel_terser//:index.js", + ], ) diff --git a/packages/terser/test/directory-args.spec.js b/packages/terser/test/directory-args.spec.js index 6a50ed82ca..c2ff9a2314 100644 --- a/packages/terser/test/directory-args.spec.js +++ b/packages/terser/test/directory-args.spec.js @@ -1,8 +1,11 @@ const {directoryArgs} = require('npm_bazel_terser/index') +const fs = require('fs'); +const path = require('path'); +const tmp = require('tmp'); describe('directoryArgs', () => { it('return a new array ref', () => { - const args = ['--source-map', '']; + const args = ['--source-map', '', '']; expect(directoryArgs(args, '')).not.toBe(args); }); @@ -11,18 +14,32 @@ describe('directoryArgs', () => { expect(directoryArgs(args)).toBe(args); }); - it('should replace the directory url with the file url', () => { + it('should set the correct file url and souremap content', () => { + const out = tmp.dirSync().name; + const input = path.join(out, 'file.js'); + const output = '/test/file.js'; const args = [ '--ie8', '--source-map', - `root='http://foo.com/src',url='some_wrong_name'`, + `root='http://foo.com/src',url='some_wrong_name',content=inline`, '--keep-fnames', ]; - const output = '/test/file.js'; - expect(directoryArgs(args, output)).toEqual([ + // if no corresponding map file exists then sourcemap content should + // be left as inline + expect(directoryArgs(args, input, output)).toEqual([ + '--ie8', + '--source-map', + `root='http://foo.com/src',url='${path.basename(output)}.map',content=inline`, + '--keep-fnames', + ]); + // if a corresponding map file exists then sourcemap content should be set + // to the map file + fs.writeFileSync(`${input}.map`, ''); + expect(directoryArgs(args, input, output)).toEqual([ '--ie8', '--source-map', - `root='http://foo.com/src',url='file.js.map'`, + `root='http://foo.com/src',url='${path.basename(output)}.map',content='${ + input.replace(/\\/g, '/')}.map'`, '--keep-fnames', ]); }); diff --git a/packages/terser/test/directory_input/BUILD.bazel b/packages/terser/test/directory_input/BUILD.bazel index fe7c7f93e7..d38e73c2e4 100644 --- a/packages/terser/test/directory_input/BUILD.bazel +++ b/packages/terser/test/directory_input/BUILD.bazel @@ -1,8 +1,7 @@ +load("@build_bazel_rules_nodejs//:tools/declare_directory.bzl", "declare_directory") load("@npm_bazel_jasmine//:index.from_src.bzl", "jasmine_node_test") load("@npm_bazel_terser//:index.from_src.bzl", "terser_minified") -load(":rule.bzl", "declare_directory") -# Check that filegroups work declare_directory( name = "dir", srcs = glob(["input*.js"]), diff --git a/packages/terser/test/sourcemap/BUILD.bazel b/packages/terser/test/sourcemap/BUILD.bazel index b8bc551b89..6dd810ea04 100644 --- a/packages/terser/test/sourcemap/BUILD.bazel +++ b/packages/terser/test/sourcemap/BUILD.bazel @@ -1,3 +1,4 @@ +load("@build_bazel_rules_nodejs//:tools/declare_directory.bzl", "declare_directory") load("@npm_bazel_jasmine//:index.from_src.bzl", "jasmine_node_test") load("@npm_bazel_terser//:index.from_src.bzl", "terser_minified") @@ -24,3 +25,27 @@ jasmine_node_test( ":src1.min", ], ) + +declare_directory( + name = "dir", + srcs = [ + "src1.js", + "src1.js.map", + ], +) + +terser_minified( + name = "dir.min", + src = "dir", +) + +jasmine_node_test( + name = "directory_test", + srcs = [ + "directory_spec.js", + ], + data = ["@npm//source-map"], + deps = [ + ":dir.min", + ], +) diff --git a/packages/terser/test/sourcemap/directory_spec.js b/packages/terser/test/sourcemap/directory_spec.js new file mode 100644 index 0000000000..699031b6ba --- /dev/null +++ b/packages/terser/test/sourcemap/directory_spec.js @@ -0,0 +1,27 @@ +const fs = require('fs'); +const sm = require('source-map'); +const path = require('path'); +const {runfiles} = require('build_bazel_rules_nodejs/internal/linker'); + +describe('terser on a directory with map files', () => { + it('should produce an output for each input', () => { + const out = runfiles.resolvePackageRelative('dir.min'); + expect(fs.existsSync(out + '/src1.js')).toBeTruthy(); + }); + + it('should produce a sourcemap output', async () => { + const out = runfiles.resolvePackageRelative('dir.min'); + const file = require.resolve(out + '/src1.js.map'); + const rawSourceMap = JSON.parse(fs.readFileSync(file, 'utf-8')); + await sm.SourceMapConsumer.with(rawSourceMap, null, consumer => { + const pos = consumer.originalPositionFor( + // position of MyClass in terser_minified output src1.min.js + // depends on DEBUG flag + !process.env['DEBUG'] ? {line: 1, column: 18} : {line: 3, column: 5}); + expect(pos.source).toBe('src1.ts'); + expect(pos.line).toBe(2); + expect(pos.column).toBe(14); + expect(pos.name).toBe('MyClass'); + }); + }); +}); \ No newline at end of file diff --git a/packages/terser/test/directory_input/rule.bzl b/tools/declare_directory.bzl similarity index 100% rename from packages/terser/test/directory_input/rule.bzl rename to tools/declare_directory.bzl