diff --git a/src/index.js b/src/index.js index 145a83ca..ecef4d00 100644 --- a/src/index.js +++ b/src/index.js @@ -12,6 +12,7 @@ import serialize from 'serialize-javascript'; import schema from './options.json'; import Uglify from './uglify'; import versions from './uglify/versions'; +import utils from './utils'; const warningRegex = /\[.+:([0-9]+),([0-9]+)\]/; @@ -122,9 +123,18 @@ class UglifyJsPlugin { const { source, map } = asset.sourceAndMap(); input = source; - inputSourceMap = map; - sourceMap = new SourceMapConsumer(inputSourceMap); + if (utils.isSourceMap(map)) { + inputSourceMap = map; + sourceMap = new SourceMapConsumer(inputSourceMap); + } else { + inputSourceMap = map; + sourceMap = null; + + compilation.warnings.push( + new Error(`${file} contain invalid source map`), + ); + } } else { input = asset.source(); inputSourceMap = null; diff --git a/src/utils/index.js b/src/utils/index.js new file mode 100644 index 00000000..37b63c9f --- /dev/null +++ b/src/utils/index.js @@ -0,0 +1,13 @@ +function isSourceMap(input) { + // All required options for `new SourceMapConsumer(...options)` + // https://github.com/mozilla/source-map#new-sourcemapconsumerrawsourcemap + return Boolean(input && + input.version && + input.sources && + input.names && + input.mappings); +} + +export default { + isSourceMap, +}; diff --git a/test/__snapshots__/source-map-options.test.js.snap b/test/__snapshots__/source-map-options.test.js.snap index d6d27cfd..b750e4b0 100644 --- a/test/__snapshots__/source-map-options.test.js.snap +++ b/test/__snapshots__/source-map-options.test.js.snap @@ -1,5 +1,13 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`when options.sourceMap true and options.parallel true compilation handler when called optimize-chunk-assets handler only calls callback once: errors 1`] = `Array []`; + +exports[`when options.sourceMap true and options.parallel true compilation handler when called optimize-chunk-assets handler only calls callback once: warnings 1`] = ` +Array [ + [Error: test4.js contain invalid source map], +] +`; + exports[`when options.sourceMap true and options.parallel true matches snapshot: asset main.0c220ec66316af2c1b24.js 1`] = `"webpackJsonp([0],[function(o,n){o.exports=function(){console.log(7)}}],[0]);"`; exports[`when options.sourceMap true and options.parallel true matches snapshot: asset manifest.d6857f782c13a99b5917.js 1`] = `"!function(r){var n=window.webpackJsonp;window.webpackJsonp=function(e,u,c){for(var f,i,p,a=0,l=[];a { beforeEach(() => { chunkPluginEnvironment = new PluginEnvironment(); compilation = chunkPluginEnvironment.getEnvironmentStub(); - compilation.assets = assets; + compilation.assets = Object.assign({}, assets); compilation.errors = []; workerFarm.mockClear(); @@ -183,7 +183,8 @@ describe('when options.parallel', () => { beforeEach(() => { chunkPluginEnvironment = new PluginEnvironment(); compilation = chunkPluginEnvironment.getEnvironmentStub(); - compilation.assets = assets; + compilation.assets = Object.assign({}, assets); + compilation.warnings = []; compilation.errors = []; workerFarm.mockClear(); @@ -290,7 +291,8 @@ describe('when options.parallel', () => { beforeEach(() => { chunkPluginEnvironment = new PluginEnvironment(); compilation = chunkPluginEnvironment.getEnvironmentStub(); - compilation.assets = assets; + compilation.assets = Object.assign({}, assets); + compilation.warnings = []; compilation.errors = []; workerFarm.mockClear(); diff --git a/test/source-map-options.test.js b/test/source-map-options.test.js index 2342898b..1c220f0d 100644 --- a/test/source-map-options.test.js +++ b/test/source-map-options.test.js @@ -20,6 +20,14 @@ describe('when options.sourceMap', () => { 'test3.js': { source: () => 'function test3(foo) { foo = 1; }', }, + 'test4.js': { + sourceAndMap: () => { + return { + source: 'function foo(x) { if (x) { return bar(); not_called1(); } }', + map: null, + }; + }, + }, }; describe('true', () => { @@ -62,7 +70,8 @@ describe('when options.sourceMap', () => { beforeEach(() => { chunkPluginEnvironment = new PluginEnvironment(); compilation = chunkPluginEnvironment.getEnvironmentStub(); - compilation.assets = assets; + compilation.assets = Object.assign({}, assets); + compilation.warnings = []; compilation.errors = []; eventBinding.handler(compilation); @@ -107,8 +116,10 @@ describe('when options.sourceMap', () => { it('only calls callback once', (done) => { callback = jest.fn(); compilationEventBinding.handler([{ - files: ['test.js', 'test1.js', 'test2.js', 'test3.js'], + files: ['test.js', 'test1.js', 'test2.js', 'test3.js', 'test4.js'], }], () => { + expect(compilation.warnings).toMatchSnapshot('warnings'); + expect(compilation.errors).toMatchSnapshot('errors'); callback(); expect(callback.mock.calls.length).toBe(1); done(); @@ -183,7 +194,8 @@ describe('when options.sourceMap', () => { beforeEach(() => { chunkPluginEnvironment = new PluginEnvironment(); compilation = chunkPluginEnvironment.getEnvironmentStub(); - compilation.assets = assets; + compilation.assets = Object.assign({}, assets); + compilation.warnings = []; compilation.errors = []; eventBinding.handler(compilation); @@ -228,8 +240,10 @@ describe('when options.sourceMap', () => { it('only calls callback once', (done) => { callback = jest.fn(); compilationEventBinding.handler([{ - files: ['test.js', 'test1.js', 'test2.js', 'test3.js'], + files: ['test.js', 'test1.js', 'test2.js', 'test3.js', 'test4.js'], }], () => { + expect(compilation.warnings).toMatchSnapshot('warnings'); + expect(compilation.errors).toMatchSnapshot('errors'); callback(); expect(callback.mock.calls.length).toBe(1); done(); diff --git a/test/utils/index.test.js b/test/utils/index.test.js new file mode 100644 index 00000000..3899b084 --- /dev/null +++ b/test/utils/index.test.js @@ -0,0 +1,21 @@ +import utils from '../../src/utils'; + +describe('utils', () => { + it('isSourceMap', () => { + const rawSourceMap = { + version: 3, + file: 'min.js', + names: ['bar', 'baz', 'n'], + sources: ['one.js', 'two.js'], + sourceRoot: 'http://example.com/www/js/', + mappings: 'CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID;CCDb,IAAI,IAAM,SAAUE,GAClB,OAAOA', + }; + + expect(utils.isSourceMap(null)).toBe(false); + expect(utils.isSourceMap()).toBe(false); + expect(utils.isSourceMap({})).toBe(false); + expect(utils.isSourceMap([])).toBe(false); + expect(utils.isSourceMap('foo')).toBe(false); + expect(utils.isSourceMap(rawSourceMap)).toBe(true); + }); +});