Skip to content

Commit

Permalink
fix: respect environment options for terser and swc compress options (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander-akait committed Aug 12, 2022
1 parent 64f2ff5 commit 29bbc3a
Show file tree
Hide file tree
Showing 8 changed files with 857 additions and 654 deletions.
1,327 changes: 693 additions & 634 deletions package-lock.json

Large diffs are not rendered by default.

37 changes: 33 additions & 4 deletions src/utils.js
@@ -1,7 +1,10 @@
/** @typedef {import("@jridgewell/trace-mapping").SourceMapInput} SourceMapInput */
/** @typedef {import("terser").FormatOptions} TerserFormatOptions */
/** @typedef {import("terser").MinifyOptions} TerserOptions */
/** @typedef {import("terser").CompressOptions} TerserCompressOptions */
/** @typedef {import("terser").ECMA} TerserECMA */
/** @typedef {import("@swc/core").JsMinifyOptions} SwcMinifyOptions */
/** @typedef {import("@swc/core").TerserCompressOptions} SwcCompressOptions */
/** @typedef {import("./index.js").ExtractCommentsOptions} ExtractCommentsOptions */
/** @typedef {import("./index.js").ExtractCommentsFunction} ExtractCommentsFunction */
/** @typedef {import("./index.js").ExtractCommentsCondition} ExtractCommentsCondition */
Expand Down Expand Up @@ -219,15 +222,15 @@ async function terserMinify(

/**
* @param {PredefinedOptions & TerserOptions} [terserOptions={}]
* @returns {TerserOptions & { sourceMap: undefined } & ({ output: TerserFormatOptions & { beautify: boolean } } | { format: TerserFormatOptions & { beautify: boolean } })}
* @returns {TerserOptions & { sourceMap: undefined } & { compress: TerserCompressOptions } & ({ output: TerserFormatOptions & { beautify: boolean } } | { format: TerserFormatOptions & { beautify: boolean } })}
*/
const buildTerserOptions = (terserOptions = {}) => {
// Need deep copy objects to avoid https://github.com/terser/terser/issues/366
return {
...terserOptions,
compress:
typeof terserOptions.compress === "boolean"
? terserOptions.compress
? {}
: { ...terserOptions.compress },
// ecma: terserOptions.ecma,
// ie8: terserOptions.ie8,
Expand Down Expand Up @@ -280,6 +283,19 @@ async function terserMinify(
);
}

// More optimizations
if (typeof terserOptions.compress.ecma === "undefined") {
terserOptions.compress.ecma = terserOptions.ecma;
}

// https://github.com/webpack/webpack/issues/16135
if (
terserOptions.ecma === 5 &&
typeof terserOptions.compress.arrows === "undefined"
) {
terserOptions.compress.arrows = false;
}

const [[filename, code]] = Object.entries(input);
const result = await minify({ [filename]: code }, terserOptions);

Expand Down Expand Up @@ -536,15 +552,15 @@ uglifyJsMinify.getMinimizerVersion = () => {
async function swcMinify(input, sourceMap, minimizerOptions) {
/**
* @param {PredefinedOptions & import("@swc/core").JsMinifyOptions} [swcOptions={}]
* @returns {import("@swc/core").JsMinifyOptions & { sourceMap: undefined }}
* @returns {SwcMinifyOptions & { sourceMap: undefined } & { compress: SwcCompressOptions }}
*/
const buildSwcOptions = (swcOptions = {}) => {
// Need deep copy objects to avoid https://github.com/terser/terser/issues/366
return {
...swcOptions,
compress:
typeof swcOptions.compress === "boolean"
? swcOptions.compress
? {}
: { ...swcOptions.compress },
mangle:
swcOptions.mangle == null
Expand Down Expand Up @@ -574,6 +590,19 @@ async function swcMinify(input, sourceMap, minimizerOptions) {
swcOptions.sourceMap = true;
}

// More optimizations
if (typeof swcOptions.compress.ecma === "undefined") {
swcOptions.compress.ecma = swcOptions.ecma;
}

// https://github.com/webpack/webpack/issues/16135
if (
swcOptions.ecma === 5 &&
typeof swcOptions.compress.arrows === "undefined"
) {
swcOptions.compress.arrows = false;
}

const [[filename, code]] = Object.entries(input);
const result = await swc.minify(code, swcOptions);

Expand Down
6 changes: 3 additions & 3 deletions test/__snapshots__/minify-option.test.js.snap
Expand Up @@ -119,7 +119,7 @@ exports[`minify option should work using when the \`minify\` option is \`esbuild
exports[`minify option should work using when the \`minify\` option is \`swcMinify\` and ECMA modules output: assets 1`] = `
Object {
"main.js": "var a={};a.d=(b,c)=>{for(var d in c)a.o(c,d)&&!a.o(b,d)&&Object.defineProperty(b,d,{enumerable:!0,get:c[d]})},a.o=(a,b)=>Object.prototype.hasOwnProperty.call(a,b);var b={};function c(){console.log(11)}a.d(b,{Z:()=>d}),c();let d=c;var e=b.Z;export{e as default}",
"main.js": "var e={};e.d=(r,o)=>{for(var a in o)e.o(o,a)&&!e.o(r,a)&&Object.defineProperty(r,a,{enumerable:!0,get:o[a]})},e.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r);var r={};function o(){console.log(11)}e.d(r,{Z:()=>a}),o();let a=o;var t=r.Z;export{t as default}",
}
`;
Expand All @@ -139,7 +139,7 @@ exports[`minify option should work using when the \`minify\` option is \`swcMini
exports[`minify option should work using when the \`minify\` option is \`swcMinify\` and generate source maps: assets 1`] = `
Object {
"main.js": "(()=>{var a={791(a){a.exports=function(){console.log(7)}}},b={};function c(d){var e=b[d];if(void 0!==e)return e.exports;var f=b[d]={exports:{}};return a[d](f,f.exports,c),f.exports}var d=c(791)})()
"main.js": "(()=>{var r={791(r){r.exports=function(){console.log(7)}}},o={};function t(e){var n=o[e];if(void 0!==n)return n.exports;var p=o[e]={exports:{}};return r[e](p,p.exports,t),p.exports}var e=t(791)})()
//# sourceMappingURL=main.js.map",
"main.js.map": "{\\"version\\":3,\\"file\\":\\"main.js\\",\\"mappings\\":\\"oBAKAA,CAAM,CAACC,OAAO,CAAG,UAAe,CAE9BC,OAAO,CAACC,GAAG,CAACC,CAAS,CAAC,CACvB,C,ECPGC,CAAwB,CAAG,EAAE,UAGxBC,CAAmB,CAACC,CAAQ,CAAE,CAEtC,IAAIC,CAAY,CAAGH,CAAwB,CAACE,CAAQ,CAAC,IACjDC,KAAiBC,CAAS,GAA1BD,CAAY,CACf,OAAOA,CAAY,CAACP,OAAO,KAGxBD,CAAM,CAAGK,CAAwB,CAACE,CAAQ,CAAC,CAAG,CAGjDN,OAAO,CAAE,EAAE,CACX,QAGDS,CAAmB,CAACH,CAAQ,CAAC,CAACP,CAAM,CAAEA,CAAM,CAACC,OAAO,CAAEK,CAAmB,CAAC,CAGnEN,CAAM,CAACC,OAAO,CACrB,ICnBGU,CAAmB,CAAGL,CAAmB,CAAC,GAAG,CAAC,C\\",\\"sources\\":[\\"webpack://terser-webpack-plugin/./test/fixtures/entry.js\\",\\"webpack://terser-webpack-plugin/webpack/bootstrap\\",\\"webpack://terser-webpack-plugin/webpack/startup\\"],\\"sourcesContent\\":[\\"// foo\\\\n/* @preserve*/\\\\n// bar\\\\nconst a = 2 + 2;\\\\n\\\\nmodule.exports = function Foo() {\\\\n const b = 2 + 2;\\\\n console.log(b + 1 + 2);\\\\n};\\\\n\\",\\"// The module cache\\\\nvar __webpack_module_cache__ = {};\\\\n\\\\n// The require function\\\\nfunction __webpack_require__(moduleId) {\\\\n\\\\t// Check if module is in cache\\\\n\\\\tvar cachedModule = __webpack_module_cache__[moduleId];\\\\n\\\\tif (cachedModule !== undefined) {\\\\n\\\\t\\\\treturn cachedModule.exports;\\\\n\\\\t}\\\\n\\\\t// Create a new module (and put it into the cache)\\\\n\\\\tvar module = __webpack_module_cache__[moduleId] = {\\\\n\\\\t\\\\t// no module.id needed\\\\n\\\\t\\\\t// no module.loaded needed\\\\n\\\\t\\\\texports: {}\\\\n\\\\t};\\\\n\\\\n\\\\t// Execute the module function\\\\n\\\\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\\\\n\\\\n\\\\t// Return the exports of the module\\\\n\\\\treturn module.exports;\\\\n}\\\\n\\\\n\\",\\"// startup\\\\n// Load entry module and return exports\\\\n// This entry module is referenced by other modules so it can't be inlined\\\\nvar __webpack_exports__ = __webpack_require__(791);\\\\n\\"],\\"names\\":[\\"module\\",\\"exports\\",\\"console\\",\\"log\\",\\"b\\",\\"__webpack_module_cache__\\",\\"__webpack_require__\\",\\"moduleId\\",\\"cachedModule\\",\\"undefined\\",\\"__webpack_modules__\\",\\"__webpack_exports__\\"],\\"sourceRoot\\":\\"\\"}",
}
Expand All @@ -160,7 +160,7 @@ exports[`minify option should work using when the \`minify\` option is \`swcMini
exports[`minify option should work using when the \`minify\` option is \`swcMinify\`: assets 1`] = `
Object {
"main.js": "(()=>{var a={791(a){a.exports=function(){console.log(7)}}},b={};function c(d){var e=b[d];if(void 0!==e)return e.exports;var f=b[d]={exports:{}};return a[d](f,f.exports,c),f.exports}var d=c(791)})()",
"main.js": "(()=>{var r={791(r){r.exports=function(){console.log(7)}}},o={};function t(e){var n=o[e];if(void 0!==n)return n.exports;var p=o[e]={exports:{}};return r[e](p,p.exports,t),p.exports}var e=t(791)})()",
}
`;
Expand Down
70 changes: 57 additions & 13 deletions test/__snapshots__/terserOptions-option.test.js.snap
Expand Up @@ -12,10 +12,7 @@ exports[`terserOptions option should match snapshot for the "compress" option wi

exports[`terserOptions option should match snapshot for the "compress" option with the "false" value: assets 1`] = `
Object {
"main.js": "/*! For license information please see main.js.LICENSE.txt */
(()=>{var r={791:r=>{const n=null&&2+2;r.exports=function r(){const n=2+2;console.log(n+1+2)}}};var n={};function o(t){var e=n[t];if(e!==undefined){return e.exports}var s=n[t]={exports:{}};r[t](s,s.exports,o);return s.exports}var t=o(791)})();",
"main.js.LICENSE.txt": "/* @preserve*/
",
"main.js": "(()=>{var r={791:r=>{r.exports=function(){console.log(7)}}},o={};(function t(e){var n=o[e];if(void 0!==n)return n.exports;var s=o[e]={exports:{}};return r[e](s,s.exports,t),s.exports})(791)})();",
}
`;

Expand All @@ -38,7 +35,7 @@ Object {
"main.js": "!function() {
var __webpack_modules__ = {
931: function(module) {
var Person = {
var abc, Person = {
firstName: null,
lastName: null
}, Employee = Object.create(Person, {
Expand All @@ -60,7 +57,13 @@ Object {
Person: Person,
Employee: Employee,
Manager: Manager
};
}, abc = {
data() {
return {
a: 2
};
}
}, console.log(abc);
}
}, __webpack_module_cache__ = {};
(function __webpack_require__(moduleId) {
Expand All @@ -85,7 +88,7 @@ Object {
"main.js": "!function() {
var __webpack_modules__ = {
931: function(module) {
var Person = {
var abc, Person = {
firstName: null,
lastName: null
}, Employee = Object.create(Person, {
Expand All @@ -107,7 +110,13 @@ Object {
Person: Person,
Employee: Employee,
Manager: Manager
};
}, abc = {
data() {
return {
a: 2
};
}
}, console.log(abc);
}
}, __webpack_module_cache__ = {};
(function __webpack_require__(moduleId) {
Expand All @@ -132,7 +141,7 @@ Object {
"main.js": "(() => {
var __webpack_modules__ = {
931: module => {
var Person = {
var abc, Person = {
firstName: null,
lastName: null
}, Employee = Object.create(Person, {
Expand All @@ -154,7 +163,11 @@ Object {
Person,
Employee,
Manager
};
}, abc = {
data: () => ({
a: 2
})
}, console.log(abc);
}
}, __webpack_module_cache__ = {};
(function __webpack_require__(moduleId) {
Expand All @@ -174,12 +187,22 @@ exports[`terserOptions option should match snapshot for the "ecma" and set the o

exports[`terserOptions option should match snapshot for the "ecma" and set the option depending on the "output.environment" option ("es2020"): warnings 1`] = `Array []`;

exports[`terserOptions option should match snapshot for the "ecma" option with the "5" value ("swc"): assets 1`] = `
Object {
"main.js": "(()=>{var __webpack_modules__={931:module=>{var Person={firstName:null,lastName:null},Employee=Object.create(Person,{id:{value:null,enumerable:!0,configurable:!0,writable:!0}}),Manager=Object.create(Employee,{department:{value:null,enumerable:!0,configurable:!0,writable:!0}});module.exports={Person:Person,Employee:Employee,Manager:Manager},function(){var abc={data(){return{a:2}}};console.log(abc)}()}},__webpack_module_cache__={};function __webpack_require__(moduleId){var cachedModule=__webpack_module_cache__[moduleId];if(void 0!==cachedModule)return cachedModule.exports;var module=__webpack_module_cache__[moduleId]={exports:{}};return __webpack_modules__[moduleId](module,module.exports,__webpack_require__),module.exports}var __webpack_exports__=__webpack_require__(931)})()",
}
`;

exports[`terserOptions option should match snapshot for the "ecma" option with the "5" value ("swc"): errors 1`] = `Array []`;

exports[`terserOptions option should match snapshot for the "ecma" option with the "5" value ("swc"): warnings 1`] = `Array []`;

exports[`terserOptions option should match snapshot for the "ecma" option with the "5" value: assets 1`] = `
Object {
"main.js": "(() => {
var __webpack_modules__ = {
931: module => {
var Person = {
var abc, Person = {
firstName: null,
lastName: null
}, Employee = Object.create(Person, {
Expand All @@ -201,7 +224,13 @@ Object {
Person: Person,
Employee: Employee,
Manager: Manager
};
}, abc = {
data() {
return {
a: 2
};
}
}, console.log(abc);
}
}, __webpack_module_cache__ = {};
(function __webpack_require__(moduleId) {
Expand All @@ -221,12 +250,27 @@ exports[`terserOptions option should match snapshot for the "ecma" option with t

exports[`terserOptions option should match snapshot for the "ecma" option with the "5" value: warnings 1`] = `Array []`;

exports[`terserOptions option should match snapshot for the "ecma" option with the "6" value ("swc"): assets 1`] = `
Object {
"main.js": "(()=>{var __webpack_modules__={513(module){console.log({data:()=>({a:2})}),module.exports=class{constructor(principal,years,rate){this.principal=principal,this.years=years,this.rate=rate}get monthlyPayment(){let monthlyRate=this.rate/100/12;return this.principal*monthlyRate/(1-Math.pow(1/(1+monthlyRate),12*this.years))}get amortization(){let monthlyPayment=this.monthlyPayment,monthlyRate=this.rate/100/12,balance=this.principal,amortization=[];for(let y=0;y<this.years;y++){let interestY=0,principalY=0;for(let m=0;m<12;m++){let interestM=balance*monthlyRate,principalM=monthlyPayment-interestM;interestY+=interestM,principalY+=principalM,balance-=principalM}amortization.push({principalY,interestY,balance})}return amortization}}}},__webpack_module_cache__={};function __webpack_require__(moduleId){var cachedModule=__webpack_module_cache__[moduleId];if(void 0!==cachedModule)return cachedModule.exports;var module=__webpack_module_cache__[moduleId]={exports:{}};return __webpack_modules__[moduleId](module,module.exports,__webpack_require__),module.exports}var __webpack_exports__=__webpack_require__(513)})()",
}
`;

exports[`terserOptions option should match snapshot for the "ecma" option with the "6" value ("swc"): errors 1`] = `Array []`;

exports[`terserOptions option should match snapshot for the "ecma" option with the "6" value ("swc"): warnings 1`] = `Array []`;

exports[`terserOptions option should match snapshot for the "ecma" option with the "6" value: assets 1`] = `
Object {
"main.js": "(() => {
var __webpack_modules__ = {
513: module => {
module.exports = class {
var abc;
abc = {
data: () => ({
a: 2
})
}, console.log(abc), module.exports = class {
constructor(principal, years, rate) {
this.principal = principal, this.years = years, this.rate = rate;
}
Expand Down
11 changes: 11 additions & 0 deletions test/fixtures/ecma-5/entry.js
Expand Up @@ -28,3 +28,14 @@ module.exports = {
Employee: Employee,
Manager: Manager
};

(function() {
var zzz = {};
var abc = {
data() {
return {
a: 2
};
}};
console.log(abc)
})();
11 changes: 11 additions & 0 deletions test/fixtures/ecma-6/entry.js
Expand Up @@ -34,4 +34,15 @@ class Mortgage {
}
}

(function() {
var zzz = {};
var abc = {
data() {
return {
a: 2
};
}};
console.log(abc)
})();

module.exports = Mortgage;
46 changes: 46 additions & 0 deletions test/terserOptions-option.test.js
Expand Up @@ -99,6 +99,29 @@ describe("terserOptions option", () => {
expect(getWarnings(stats)).toMatchSnapshot("warnings");
});

it('should match snapshot for the "ecma" option with the "5" value ("swc")', async () => {
const compiler = getCompiler({
entry: path.resolve(__dirname, "./fixtures/ecma-5/entry.js"),
});

new TerserPlugin({
minify: TerserPlugin.swcMinify,
terserOptions: {
ecma: 5,
mangle: false,
format: {
beautify: true,
},
},
}).apply(compiler);

const stats = await compile(compiler);

expect(readsAssets(compiler, stats)).toMatchSnapshot("assets");
expect(getErrors(stats)).toMatchSnapshot("errors");
expect(getWarnings(stats)).toMatchSnapshot("warnings");
});

it('should match snapshot for the "ecma" option with the "6" value', async () => {
const compiler = getCompiler({
entry: path.resolve(__dirname, "./fixtures/ecma-6/entry.js"),
Expand All @@ -121,6 +144,29 @@ describe("terserOptions option", () => {
expect(getWarnings(stats)).toMatchSnapshot("warnings");
});

it('should match snapshot for the "ecma" option with the "6" value ("swc")', async () => {
const compiler = getCompiler({
entry: path.resolve(__dirname, "./fixtures/ecma-6/entry.js"),
});

new TerserPlugin({
minify: TerserPlugin.swcMinify,
terserOptions: {
ecma: 6,
mangle: false,
format: {
beautify: true,
},
},
}).apply(compiler);

const stats = await compile(compiler);

expect(readsAssets(compiler, stats)).toMatchSnapshot("assets");
expect(getErrors(stats)).toMatchSnapshot("errors");
expect(getWarnings(stats)).toMatchSnapshot("warnings");
});

it('should match snapshot for the "ecma" option with the "7" value', async () => {
const compiler = getCompiler({
entry: path.resolve(__dirname, "./fixtures/ecma-7/entry.js"),
Expand Down
3 changes: 3 additions & 0 deletions types/utils.d.ts
Expand Up @@ -2,7 +2,10 @@ export type Task<T> = () => Promise<T>;
export type SourceMapInput = import("@jridgewell/trace-mapping").SourceMapInput;
export type TerserFormatOptions = import("terser").FormatOptions;
export type TerserOptions = import("terser").MinifyOptions;
export type TerserCompressOptions = import("terser").CompressOptions;
export type TerserECMA = import("terser").ECMA;
export type SwcMinifyOptions = import("@swc/core").JsMinifyOptions;
export type SwcCompressOptions = import("@swc/core").TerserCompressOptions;
export type ExtractCommentsOptions =
import("./index.js").ExtractCommentsOptions;
export type ExtractCommentsFunction =
Expand Down

0 comments on commit 29bbc3a

Please sign in to comment.