From 9aeafc06bb7d4dab5dca55197f0287a921f7f14f Mon Sep 17 00:00:00 2001 From: FM <15306225869@163.com> Date: Fri, 22 Oct 2021 19:03:38 +0800 Subject: [PATCH] feat: add a top-level `terser` option to allow users to customize the minifier (#6752) --- .../cli-service/lib/config/terserOptions.js | 142 +++++++++++++----- packages/@vue/cli-service/lib/options.js | 6 + .../cli-service/types/ProjectOptions.d.ts | 27 ++++ 3 files changed, 139 insertions(+), 36 deletions(-) diff --git a/packages/@vue/cli-service/lib/config/terserOptions.js b/packages/@vue/cli-service/lib/config/terserOptions.js index e08948cee9..05387a5ba2 100644 --- a/packages/@vue/cli-service/lib/config/terserOptions.js +++ b/packages/@vue/cli-service/lib/config/terserOptions.js @@ -1,40 +1,110 @@ -module.exports = options => ({ - terserOptions: { - compress: { - // turn off flags with small gains to speed up minification - arrows: false, - collapse_vars: false, // 0.3kb - comparisons: false, - computed_props: false, - hoist_funs: false, - hoist_props: false, - hoist_vars: false, - inline: false, - loops: false, - negate_iife: false, - properties: false, - reduce_funcs: false, - reduce_vars: false, - switches: false, - toplevel: false, - typeofs: false, - - // a few flags with noticeable gains/speed ratio - // numbers based on out of the box vendor bundle - booleans: true, // 0.7kb - if_return: true, // 0.4kb - sequences: true, // 0.7kb - unused: true, // 2.3kb - - // required features to drop conditional branches - conditionals: true, - dead_code: true, - evaluate: true +// @ts-check +const TerserPlugin = require('terser-webpack-plugin') + +const genTerserOptions = (defaultOptions, options) => { + const userOptions = options.terser && options.terser.terserOptions + // user's config is first + return { + ...defaultOptions, + ...userOptions + } +} + +const terserMinify = (options) => ({ + terserOptions: genTerserOptions( + { + compress: { + // turn off flags with small gains to speed up minification + arrows: false, + collapse_vars: false, // 0.3kb + comparisons: false, + computed_props: false, + hoist_funs: false, + hoist_props: false, + hoist_vars: false, + inline: false, + loops: false, + negate_iife: false, + properties: false, + reduce_funcs: false, + reduce_vars: false, + switches: false, + toplevel: false, + typeofs: false, + + // a few flags with noticeable gains/speed ratio + // numbers based on out of the box vendor bundle + booleans: true, // 0.7kb + if_return: true, // 0.4kb + sequences: true, // 0.7kb + unused: true, // 2.3kb + + // required features to drop conditional branches + conditionals: true, + dead_code: true, + evaluate: true + }, + mangle: { + safari10: true + } }, - mangle: { - safari10: true - } - }, + options + ), parallel: options.parallel, extractComments: false }) + +// `terserOptions` options will be passed to `esbuild` +// Link to options - https://esbuild.github.io/api/#minify +const esbuildMinify = (options) => ({ + minify: TerserPlugin.esbuildMinify, + terserOptions: genTerserOptions( + { + minify: false, + minifyWhitespace: true, + minifyIdentifiers: false, + minifySyntax: true + }, + options + ), + parallel: options.parallel +}) + +// `terserOptions` options will be passed to `swc` (`@swc/core`) +// Link to options - https://swc.rs/docs/config-js-minify +const swcMinify = (options) => ({ + minify: TerserPlugin.swcMinify, + terserOptions: genTerserOptions( + { + compress: { + unused: true + }, + mangle: true + }, + options + ), + parallel: options.parallel +}) + +// `terserOptions` options will be passed to `uglify-js` +// Link to options - https://github.com/mishoo/UglifyJS#minify-options +const uglifyJsMinify = (options) => ({ + minify: TerserPlugin.uglifyJsMinify, + terserOptions: genTerserOptions({}, options), + parallel: options.parallel +}) + +// Currently we do not allow custom minify function +const getMinify = (options) => { + const { minify = 'terser' } = options.terser || {} + + const minifyMap = { + terser: terserMinify, + esbuild: esbuildMinify, + swc: swcMinify, + uglifyJs: uglifyJsMinify + } + return minifyMap[minify](options) +} + +module.exports = getMinify diff --git a/packages/@vue/cli-service/lib/options.js b/packages/@vue/cli-service/lib/options.js index 232192c3e6..f410504e36 100644 --- a/packages/@vue/cli-service/lib/options.js +++ b/packages/@vue/cli-service/lib/options.js @@ -59,6 +59,12 @@ const schema = createSchema(joi => joi.object({ lintOnSave: joi.any().valid(true, false, 'error', 'warning', 'default'), pwa: joi.object(), + // terser + terser: joi.object({ + minify: joi.string().valid('terser', 'esbuild', 'swc', 'uglifyJs'), + terserOptions: joi.object() + }), + // 3rd party plugin options pluginOptions: joi.object() })) diff --git a/packages/@vue/cli-service/types/ProjectOptions.d.ts b/packages/@vue/cli-service/types/ProjectOptions.d.ts index 4ea5b1fe38..8dc81eaf8b 100644 --- a/packages/@vue/cli-service/types/ProjectOptions.d.ts +++ b/packages/@vue/cli-service/types/ProjectOptions.d.ts @@ -1,6 +1,8 @@ import ChainableWebpackConfig = require('webpack-chain') import { Configuration as WebpackOptions } from 'webpack' +type PredefinedOptions = T & { [key: string]: any } + type PageEntry = string | string[]; interface PageConfig { @@ -153,6 +155,31 @@ interface ProjectOptions { */ pwa?: object; + /** + * set terser-webpack-plugin minify and terserOptions + */ + terser?: { + /** + * Supported minify: [terser](https://github.com/webpack-contrib/terser-webpack-plugin#minify), [esbuild](https://github.com/webpack-contrib/terser-webpack-plugin#esbuild), [swc](https://github.com/webpack-contrib/terser-webpack-plugin#swc), [uglifyJs](https://github.com/webpack-contrib/terser-webpack-plugin#uglify-js). currently we do not allow custom minify function + * + * In the non-terser case, you should install the corresponding package (eg. `npm i esbuild -D`) + * + */ + minify: 'terser' | 'esbuild' | 'swc' | 'uglifyJs'; + /** + * `terserOptions` options will be passed to minify + * + * [All options for `terser`](https://github.com/webpack-contrib/terser-webpack-plugin#terseroptions) + * + * [All options for `esbuild`](https://github.com/evanw/esbuild/blob/master/lib/shared/types.ts#L160-L174) + * + * [All options for `swc`](https://swc.rs/docs/config-js-minify) + * + * [All options for `uglifyJs`](https://github.com/mishoo/UglifyJS#minify-options) + */ + terserOptions?: PredefinedOptions; + }; + /** * This is an object that doesn't go through any schema validation, so it can be used to pass arbitrary options to 3rd party plugins */