From fac58cb1ee7935710b3b38662c3abbf8dc12a862 Mon Sep 17 00:00:00 2001 From: Evilebot Tnawi Date: Fri, 14 Feb 2020 18:51:19 +0300 Subject: [PATCH] fix: do not break code with shebang --- src/index.js | 29 ++++++++++++++----- ...tractComments-option.test.js.snap.webpack4 | 16 ++++++++++ ...tractComments-option.test.js.snap.webpack5 | 16 ++++++++++ test/extractComments-option.test.js | 23 +++++++++++++++ test/fixtures/shebang-1.js | 1 + test/fixtures/shebang.js | 3 ++ 6 files changed, 81 insertions(+), 7 deletions(-) create mode 100644 test/fixtures/shebang-1.js create mode 100644 test/fixtures/shebang.js diff --git a/src/index.js b/src/index.js index 4bfc77fb..a3732f29 100644 --- a/src/index.js +++ b/src/index.js @@ -275,7 +275,8 @@ class TerserPlugin { } const callback = (taskResult) => { - const { error, map, code, warnings } = taskResult; + let { code } = taskResult; + const { error, map, warnings } = taskResult; const { extractedComments } = taskResult; let sourceMap = null; @@ -299,7 +300,24 @@ class TerserPlugin { return; } + const hasExtractedComments = + commentsFilename && extractedComments && extractedComments.length > 0; + const hasBannerForExtractedComments = + hasExtractedComments && this.options.extractComments.banner !== false; + let outputSource; + let shebang; + + if ( + hasExtractedComments && + hasBannerForExtractedComments && + code.startsWith('#!') + ) { + const firstNewlinePosition = code.indexOf('\n'); + + shebang = code.substring(0, firstNewlinePosition); + code = code.substring(firstNewlinePosition + 1); + } if (map) { outputSource = new SourceMapSource( @@ -315,11 +333,7 @@ class TerserPlugin { } // Write extracted comments to commentsFilename - if ( - commentsFilename && - extractedComments && - extractedComments.length > 0 - ) { + if (hasExtractedComments) { if (!allExtractedComments[commentsFilename]) { // eslint-disable-next-line no-param-reassign allExtractedComments[commentsFilename] = []; @@ -331,7 +345,7 @@ class TerserPlugin { ].concat(extractedComments); // Add a banner to the original file - if (this.options.extractComments.banner !== false) { + if (hasBannerForExtractedComments) { let banner = this.options.extractComments.banner || `For license information please see ${path @@ -344,6 +358,7 @@ class TerserPlugin { if (banner) { outputSource = new ConcatSource( + shebang ? `${shebang}\n` : '', `/*! ${banner} */\n`, outputSource ); diff --git a/test/__snapshots__/extractComments-option.test.js.snap.webpack4 b/test/__snapshots__/extractComments-option.test.js.snap.webpack4 index d056359f..38b8ff68 100644 --- a/test/__snapshots__/extractComments-option.test.js.snap.webpack4 +++ b/test/__snapshots__/extractComments-option.test.js.snap.webpack4 @@ -734,6 +734,22 @@ exports[`extractComments option should match snapshot and extract "some" comment exports[`extractComments option should match snapshot and extract "some" comments: warnings 1`] = `Array []`; +exports[`extractComments option should match snapshot and keep shebang: assets 1`] = ` +Object { + "shebang.js": "#!/usr/bin/env node +/*! For license information please see shebang.js.LICENSE.txt */ +!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&\\"object\\"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,\\"default\\",{enumerable:!0,value:e}),2&t&&\\"string\\"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,\\"a\\",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p=\\"\\",n(n.s=0)}([function(e,t){console.log(\\"HERE\\")}]);", + "shebang.js.LICENSE.txt": "/*! Legal Comment */ +", + "shebang1.js": "#!/usr/bin/env node +!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&\\"object\\"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,\\"default\\",{enumerable:!0,value:e}),2&t&&\\"string\\"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,\\"a\\",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p=\\"\\",n(n.s=1)}([,function(e,t){console.log(\\"HERE\\")}]);", +} +`; + +exports[`extractComments option should match snapshot and keep shebang: errors 1`] = `Array []`; + +exports[`extractComments option should match snapshot and keep shebang: warnings 1`] = `Array []`; + exports[`extractComments option should match snapshot and preserve "all" and do not extract comments: assets 1`] = ` Object { "chunks/4.4.js": "(window.webpackJsonp=window.webpackJsonp||[]).push([[4],{ diff --git a/test/__snapshots__/extractComments-option.test.js.snap.webpack5 b/test/__snapshots__/extractComments-option.test.js.snap.webpack5 index 7b8df0d7..325a96a1 100644 --- a/test/__snapshots__/extractComments-option.test.js.snap.webpack5 +++ b/test/__snapshots__/extractComments-option.test.js.snap.webpack5 @@ -634,6 +634,22 @@ exports[`extractComments option should match snapshot and extract "some" comment exports[`extractComments option should match snapshot and extract "some" comments: warnings 1`] = `Array []`; +exports[`extractComments option should match snapshot and keep shebang: assets 1`] = ` +Object { + "shebang.js": "#!/usr/bin/env node +/*! For license information please see shebang.js.LICENSE.txt */ +console.log(\\"HERE\\");", + "shebang.js.LICENSE.txt": "/*! Legal Comment */ +", + "shebang1.js": "#!/usr/bin/env node +console.log(\\"HERE\\");", +} +`; + +exports[`extractComments option should match snapshot and keep shebang: errors 1`] = `Array []`; + +exports[`extractComments option should match snapshot and keep shebang: warnings 1`] = `Array []`; + exports[`extractComments option should match snapshot and preserve "all" and do not extract comments: assets 1`] = ` Object { "chunks/627.627.js": "(window.webpackJsonp=window.webpackJsonp||[]).push([[627],{ diff --git a/test/extractComments-option.test.js b/test/extractComments-option.test.js index ce28a346..5b271f5f 100644 --- a/test/extractComments-option.test.js +++ b/test/extractComments-option.test.js @@ -1,3 +1,5 @@ +import webpack from 'webpack'; + import TerserPlugin from '../src/index'; import { @@ -642,4 +644,25 @@ describe('extractComments option', () => { expect(getErrors(stats)).toMatchSnapshot('errors'); expect(getWarnings(stats)).toMatchSnapshot('warnings'); }); + + it('should match snapshot and keep shebang', async () => { + compiler = getCompiler({ + entry: { + shebang: `${__dirname}/fixtures/shebang.js`, + shebang1: `${__dirname}/fixtures/shebang-1.js`, + }, + target: 'node', + plugins: [ + new webpack.BannerPlugin({ banner: '#!/usr/bin/env node', raw: true }), + ], + }); + + new TerserPlugin().apply(compiler); + + const stats = await compile(compiler); + + expect(readsAssets(compiler, stats)).toMatchSnapshot('assets'); + expect(getErrors(stats)).toMatchSnapshot('errors'); + expect(getWarnings(stats)).toMatchSnapshot('warnings'); + }); }); diff --git a/test/fixtures/shebang-1.js b/test/fixtures/shebang-1.js new file mode 100644 index 00000000..2457f618 --- /dev/null +++ b/test/fixtures/shebang-1.js @@ -0,0 +1 @@ +console.log('HERE'); diff --git a/test/fixtures/shebang.js b/test/fixtures/shebang.js new file mode 100644 index 00000000..0937a7d7 --- /dev/null +++ b/test/fixtures/shebang.js @@ -0,0 +1,3 @@ +/* Comment */ +/*! Legal Comment */ +console.log('HERE');