Skip to content

Commit

Permalink
fix: compatibility with the format option for terser
Browse files Browse the repository at this point in the history
  • Loading branch information
evilebottnawi committed Oct 27, 2020
1 parent a79ea67 commit b944353
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 23 deletions.
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,9 @@ module.exports = {
compress: {},
mangle: true, // Note `mangle.properties` is `false` by default.
module: false,
// Deprecated
output: null,
format: null,
toplevel: false,
nameCache: null,
ie8: false,
Expand All @@ -256,7 +258,7 @@ Default: `true`
Whether comments shall be extracted to a separate file, (see [details](https://github.com/webpack/webpack/commit/71933e979e51c533b432658d5e37917f9e71595a)).
By default extract only comments using `/^\**!|@preserve|@license|@cc_on/i` regexp condition and remove remaining comments.
If the original file is named `foo.js`, then the comments will be stored to `foo.js.LICENSE.txt`.
The `terserOptions.output.comments` option specifies whether the comment will be preserved, i.e. it is possible to preserve some comments (e.g. annotations) while extracting others or even preserving comments that have been extracted.
The `terserOptions.format.comments` option specifies whether the comment will be preserved, i.e. it is possible to preserve some comments (e.g. annotations) while extracting others or even preserving comments that have been extracted.

#### `Boolean`

Expand Down Expand Up @@ -479,7 +481,7 @@ module.exports = {
minimizer: [
new TerserPlugin({
terserOptions: {
output: {
format: {
comments: /@license/i,
},
},
Expand All @@ -503,7 +505,7 @@ module.exports = {
minimizer: [
new TerserPlugin({
terserOptions: {
output: {
format: {
comments: false,
},
},
Expand Down
6 changes: 5 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,17 @@ import { minify as minifyFn } from './minify';
* @param {MinifyOptions} minifyOptions
*/

/**
* @typedef {ExtractCommentsCondition | ExtractCommentsObject} ExtractCommentsOptions
*/

/**
* @typedef {Object} TerserPluginOptions
* @property {Rules} [test]
* @property {Rules} [include]
* @property {Rules} [exclude]
* @property {MinifyOptions} [terserOptions]
* @property {ExtractCommentsCondition | ExtractCommentsObject} [extractComments]
* @property {ExtractCommentsOptions} [extractComments]
* @property {boolean} [parallel]
* @property {CustomMinifyFunction} [minify]
*/
Expand Down
55 changes: 36 additions & 19 deletions src/minify.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
const { minify: terserMinify } = require('terser');

/** @typedef {import("source-map").RawSourceMap} RawSourceMap */
/** @typedef {import("./index.js").ExtractCommentsOptions} ExtractCommentsOptions */
/** @typedef {import("./index.js").CustomMinifyFunction} CustomMinifyFunction */
/** @typedef {import("./index.js").MinifyOptions} MinifyOptions */
/** @typedef {import("terser").MinifyOptions} TerserMinifyOptions */
/** @typedef {import("terser").MinifyOutput} MinifyOutput */
/** @typedef {import("terser").FormatOptions} FormatOptions */
/** @typedef {import("terser").MangleOptions} MangleOptions */
/** @typedef {import("source-map").RawSourceMap} SourceMapRawSourceMap */
/** @typedef {import("./index.js").ExtractCommentsFunction} ExtractCommentsFunction */
/** @typedef {import("./index.js").ExtractCommentsCondition} ExtractCommentsCondition */

/**
* @typedef {Object} InternalMinifyOptions
* @property {string} name
* @property {string} input
* @property {any} inputSourceMap
* @property {any} extractComments
* @property {any} minify
* @property {any} minifyOptions
* @property {RawSourceMap} inputSourceMap
* @property {ExtractCommentsOptions} extractComments
* @property {CustomMinifyFunction} minify
* @property {MinifyOptions} minifyOptions
*/

/**
Expand All @@ -27,7 +30,7 @@ const { minify: terserMinify } = require('terser');
*/

/**
* @typedef {TerserMinifyOptions & { mangle: MangleOptions, output: FormatOptions & { beautify: boolean }, sourceMap: undefined }} NormalizedTerserMinifyOptions
* @typedef {TerserMinifyOptions & { sourceMap: undefined } & ({ output: FormatOptions & { beautify: boolean } } | { format: FormatOptions & { beautify: boolean } })} NormalizedTerserMinifyOptions
*/

/**
Expand All @@ -43,14 +46,13 @@ function buildTerserOptions(terserOptions = {}) {
: typeof terserOptions.mangle === 'boolean'
? terserOptions.mangle
: { ...terserOptions.mangle },
// Deprecated
output: {
beautify: false,
...terserOptions.output,
},
// Ignoring sourceMap from options
// eslint-disable-next-line no-undefined
sourceMap: undefined,
// the `output` option is deprecated
...(terserOptions.format
? { format: { beautify: false, ...terserOptions.format } }
: { output: { beautify: false, ...terserOptions.output } }),
};
}

Expand All @@ -65,15 +67,22 @@ function isObject(value) {
}

/**
* @param {any} extractComments
* @param {ExtractCommentsOptions} extractComments
* @param {NormalizedTerserMinifyOptions} terserOptions
* @param {ExtractedComments} extractedComments
* @returns {ExtractCommentsFunction}
*/
function buildComments(extractComments, terserOptions, extractedComments) {
/** @type {{ [index: string]: ExtractCommentsCondition }} */
const condition = {};
const { comments } = terserOptions.output;

let comments;

if (terserOptions.format) {
({ comments } = terserOptions.format);
} else if (terserOptions.output) {
({ comments } = terserOptions.output);
}

condition.preserve = typeof comments !== 'undefined' ? comments : false;

Expand All @@ -86,7 +95,7 @@ function buildComments(extractComments, terserOptions, extractedComments) {
condition.extract = extractComments;
} else if (typeof extractComments === 'function') {
condition.extract = extractComments;
} else if (isObject(extractComments)) {
} else if (extractComments && isObject(extractComments)) {
condition.extract =
typeof extractComments.condition === 'boolean' &&
extractComments.condition
Expand Down Expand Up @@ -213,11 +222,19 @@ async function minify(options) {
const extractedComments = [];
const { extractComments } = options;

terserOptions.output.comments = buildComments(
extractComments,
terserOptions,
extractedComments
);
if (terserOptions.output) {
terserOptions.output.comments = buildComments(
extractComments,
terserOptions,
extractedComments
);
} else if (terserOptions.format) {
terserOptions.format.comments = buildComments(
extractComments,
terserOptions,
extractedComments
);
}

const result = await terserMinify({ [name]: input }, terserOptions);

Expand Down
70 changes: 70 additions & 0 deletions test/__snapshots__/terserOptions-option.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,76 @@ exports[`terserOptions option should match snapshot for the "ecma" option with t

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

exports[`terserOptions option should match snapshot for the "format.beautify" option with "true" value: assets 1`] = `
Object {
"main.js": "(() => {
var r = {
791: r => {
r.exports = function() {
console.log(7);
};
}
}, o = {};
!function t(e) {
if (o[e]) return o[e].exports;
var n = o[e] = {
exports: {}
};
return r[e](n, n.exports, t), n.exports;
}(791);
})();",
}
`;

exports[`terserOptions option should match snapshot for the "format.beautify" option with "true" value: errors 1`] = `Array []`;

exports[`terserOptions option should match snapshot for the "format.beautify" option with "true" value: warnings 1`] = `Array []`;

exports[`terserOptions option should match snapshot for the "format.comments" option with the "true": assets 1`] = `
Object {
"main.js": "/******/(()=>{// webpackBootstrap
/******/var r={
/***/791:
/***/r=>{r.exports=function(){console.log(7)}}
/***/
/******/},o={};
/************************************************************************/
/******/ // The module cache
/******/
/******/
/************************************************************************/
/******/ // startup
/******/ // Load entry module
/******/ // This entry module is referenced by other modules so it can't be inlined
/******/!
/******/
/******/ // The require function
/******/function t(e){
/******/ // Check if module is in cache
/******/if(o[e])
/******/return o[e].exports;
/******/
/******/ // Create a new module (and put it into the cache)
/******/var n=o[e]={
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/exports:{}
/******/};
/******/
/******/ // Execute the module function
/******/
/******/
/******/ // Return the exports of the module
/******/return r[e](n,n.exports,t),n.exports;
/******/}(791)})
/******/();",
}
`;

exports[`terserOptions option should match snapshot for the "format.comments" option with the "true": errors 1`] = `Array []`;

exports[`terserOptions option should match snapshot for the "format.comments" option with the "true": warnings 1`] = `Array []`;

exports[`terserOptions option should match snapshot for the "ie8" option with the "false" value: assets 1`] = `
Object {
"main.js": "(()=>{var r={791:r=>{r.exports=function(){console.log(7)}}},o={};!function t(e){if(o[e])return o[e].exports;var n=o[e]={exports:{}};return r[e](n,n.exports,t),n.exports}(791)})();",
Expand Down
36 changes: 36 additions & 0 deletions test/terserOptions-option.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,42 @@ describe('terserOptions option', () => {
expect(getWarnings(stats)).toMatchSnapshot('warnings');
});

it('should match snapshot for the "format.beautify" option with "true" value', async () => {
const compiler = getCompiler();

new TerserPlugin({
terserOptions: {
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 "format.comments" option with the "true"', async () => {
const compiler = getCompiler();

new TerserPlugin({
terserOptions: {
format: {
comments: 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 "toplevel" option with the "false" value', async () => {
const compiler = getCompiler();

Expand Down

0 comments on commit b944353

Please sign in to comment.