å 责声æï¼TerserWebpackPlugin æ¯ç±ç¤¾åºæåç»´æ¤çç¬¬ä¸æ¹å ï¼å®å¯è½æ²¡æä¸ webpack ç¸åçæ¯æãå®å ¨çç¥æè®¸å¯è¯ï¼å¹¶ä¸å®ä¸æ¯ç± webpack ç»´æ¤çã
该æä»¶ä½¿ç¨ terser æ¥å缩 JavaScriptã
webpack v5 å¼ç®±å³å¸¦æææ°çæ¬ç terser-webpack-pluginãå¦æä½ ä½¿ç¨çæ¯ webpack v5 ææ´é«çæ¬ï¼åæ¶å¸æèªå®ä¹é
ç½®ï¼é£ä¹ä»éè¦å®è£
terser-webpack-pluginãå¦æä½¿ç¨ webpack v4ï¼åå¿
é¡»å®è£
terser-webpack-plugin v4 ççæ¬ã
é¦å
éè¦å®è£
terser-webpack-pluginï¼
npm install terser-webpack-plugin --save-dev
ç¶åå°æä»¶æ·»å å° webpack é
ç½®æä»¶ä¸ï¼ä¾å¦ï¼
webpack.config.js
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
optimization: {
minimize: true,
minimizer: [new TerserPlugin()],
},
};æ¥ä¸æ¥ï¼æç
§ä½ ä¹ æ¯çæ¹å¼è¿è¡ webpackã
åªå¯¹ devtool é项ç source-mapï¼inline-source-mapï¼hidden-source-map å nosources-source-map ææã
为ä½å¦æ¤ï¼
eval éè¿ eval("string") å
裹模åèå缩工å
·ä¸ä¼å¤çå符串ãcheap ä¸åå¨åä¿¡æ¯èå缩工å
·è¾åºçæä»¶ä¸ºåè¡æä»¶ï¼åªä¼çä¸ä¸ä¸ªæ å°ãä½¿ç¨æ¯æç devtool å¼å¯ä»¥çæ source mapã
testç±»åï¼ String|RegExp|Array<String|RegExp>
é»è®¤å¼ï¼/\.m?js(\?.*)?$/i
ç¨æ¥å¹é éè¦å缩çæä»¶ã
webpack.config.js
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
test: /\.js(\?.*)?$/i,
}),
],
},
};includeç±»åï¼ String|RegExp|Array<String|RegExp>
é»è®¤å¼ï¼ undefined
å¹é åä¸å缩çæä»¶ã
webpack.config.js
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
include: /\/includes/,
}),
],
},
};excludeç±»åï¼ String|RegExp|Array<String|RegExp>
é»è®¤å¼ï¼ undefined
å¹é ä¸éè¦å缩çæä»¶ã
webpack.config.js
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
exclude: /\/excludes/,
}),
],
},
};parallelç±»åï¼ Boolean|Number
é»è®¤å¼ï¼ true
使ç¨å¤è¿ç¨å¹¶åè¿è¡ä»¥æé«æå»ºé度ã
å¹¶åè¿è¡çé»è®¤æ°éï¼ os.cpus().length - 1 ã
å¹¶åè¿è¡å¯ä»¥æ¾èæé«æå»ºé度ï¼å æ¤å¼ºçå»ºè®®æ·»å æ¤é ç½® ã
å¦æä½ ä½¿ç¨ Circle CI æä»»ä½å ¶ä»ä¸æä¾ CPU å®é å¯ç¨æ°éçç¯å¢ï¼åéè¦æ¾å¼è®¾ç½® CPU æ°éï¼ä»¥é¿å
Error: Call retries were exceededï¼è¯·åé #143ï¼#202 ï¼ã
Booleanå¯ç¨/ç¦ç¨å¤è¿ç¨å¹¶åè¿è¡åè½ã
webpack.config.js
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
parallel: true,
}),
],
},
};Numberå¯ç¨å¤è¿ç¨å¹¶åè¿è¡å¹¶è®¾ç½®å¹¶åè¿è¡æ¬¡æ°ã
webpack.config.js
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
parallel: 4,
}),
],
},
};minifyç±»åï¼ Function
é»è®¤å¼ï¼ TerserPlugin.terserMinify
å è®¸ä½ èªå®ä¹åç¼©å½æ°ã é»è®¤æ åµä¸ï¼æä»¶ä½¿ç¨ terser åºã 对äºä½¿ç¨åæµè¯æªåå¸ççæ¬æ fork ç代ç å¾å¸®å©ã
â ï¸ å¯ç¨
parallelé项æ¶ï¼å¨minify彿°å é¨åªè½ä½¿ç¨requireã
webpack.config.js
// Can be async
const minify = (input, sourceMap, minimizerOptions, extractsComments) => {
// The `minimizerOptions` option contains option from the `terserOptions` option
// You can use `minimizerOptions.myCustomOption`
// Custom logic for extract comments
const { map, code } = require('uglify-module') // Or require('./path/to/uglify-module')
.minify(input, {
/* Your options for minification */
});
return { map, code, warnings: [], errors: [], extractedComments: [] };
};
// Used to regenerate `fullhash`/`chunkhash` between different implementation
// Example: you fix a bug in custom minimizer/custom function, but unfortunately webpack doesn't know about it, so you will get the same fullhash/chunkhash
// to avoid this you can provide version of your custom minimizer
// You don't need if you use only `contenthash`
minify.getMinimizerVersion = () => {
let packageJson;
try {
// eslint-disable-next-line global-require, import/no-extraneous-dependencies
packageJson = require('uglify-module/package.json');
} catch (error) {
// Ignore
}
return packageJson && packageJson.version;
};
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
myCustomOption: true,
},
minify,
}),
],
},
};terserOptionsç±»åï¼ Object
é»è®¤å¼ï¼ é»è®¤
Terser é 置项 ã
webpack.config.js
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
ecma: undefined,
parse: {},
compress: {},
mangle: true, // Note `mangle.properties` is `false` by default.
module: false,
// Deprecated
output: null,
format: null,
toplevel: false,
nameCache: null,
ie8: false,
keep_classnames: undefined,
keep_fnames: false,
safari10: false,
},
}),
],
},
};extractCommentsç±»åï¼ Boolean|String|RegExp|Function<(node, comment) -> Boolean|Object>|Object
é»è®¤å¼ï¼ true
æ¯å¦å°æ³¨éå¥ç¦»å°åç¬çæä»¶ä¸ï¼è¯·åé
详ç»ä¿¡æ¯ï¼ã
é»è®¤æ
åµä¸ï¼ä»
å¥ç¦» /^\**!|@preserve|@license|@cc_on/i æ£å表达å¼å¹é
çæ³¨éï¼å
¶ä½æ³¨éä¼å é¤ã
妿åå§æä»¶å为 foo.js ï¼å注éå°åå¨å° foo.js.LICENSE.txt ã
terserOptions.format.comments é项æå®æ¯å¦ä¿ç注éï¼å³å¯ä»¥å¨å¥ç¦»å
¶ä»æ³¨éæ¶ä¿çä¸äºæ³¨éï¼çè³ä¿çå·²å¥ç¦»ç注éã
Booleanå¯ç¨/ç¦ç¨å¥ç¦»æ³¨éåè½ã
webpack.config.js
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
extractComments: true,
}),
],
},
};Stringå¥ç¦» all æ some ï¼ä½¿ç¨ /^\**!|@preserve|@license|@cc_on/i æ£å表达å¼è¿è¡å¹é
ï¼æ³¨éã
webpack.config.js
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
extractComments: 'all',
}),
],
},
};RegExp䏿å®è¡¨è¾¾å¼å¹é çæææ³¨éå°ä¼è¢«å¥ç¦»å°åç¬çæä»¶ä¸ã
webpack.config.js
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
extractComments: /@extract/i,
}),
],
},
};Function<(node, comment) -> Boolean>䏿å®è¡¨è¾¾å¼å¹é çæææ³¨éå°ä¼è¢«å¥ç¦»å°åç¬çæä»¶ä¸ã
webpack.config.js
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
extractComments: (astNode, comment) => {
if (/@extract/i.test(comment.value)) {
return true;
}
return false;
},
}),
],
},
};Objectå 许èªå®ä¹å¥ç¦»æ³¨éçæ¡ä»¶ï¼æå®å¥ç¦»çæä»¶ååæ é¢ã
webpack.config.js
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
extractComments: {
condition: /^\**!|@preserve|@license|@cc_on/i,
filename: (fileData) => {
// The "fileData" argument contains object with "filename", "basename", "query" and "hash"
return `${fileData.filename}.LICENSE.txt${fileData.query}`;
},
banner: (licenseFile) => {
return `License information can be found in ${licenseFile}`;
},
},
}),
],
},
};conditionç±»åï¼ Boolean|String|RegExp|Function<(node, comment) -> Boolean|Object>
èªå®ä¹éè¦å¥ç¦»ç注éã
webpack.config.js
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
extractComments: {
condition: 'some',
filename: (fileData) => {
// The "fileData" argument contains object with "filename", "basename", "query" and "hash"
return `${fileData.filename}.LICENSE.txt${fileData.query}`;
},
banner: (licenseFile) => {
return `License information can be found in ${licenseFile}`;
},
},
}),
],
},
};filenameç±»åï¼ String|Function<(string) -> String>
é»è®¤å¼ï¼ [file].LICENSE.txt [query]
å¯ç¨çå ä½ç¬¦ï¼ [file] ï¼ [query] å [filebase] ï¼webpack 5 ä½¿ç¨ [base] ï¼ã
å¥ç¦»åºæ¥ç注éå°è¢«åå¨å°çæä»¶çæä»¶åã
é»è®¤æ¯å°åç¼ .LICENSE.txt éå å°åå§æä»¶åã
â ï¸ æä»¬å¼ºç建议使ç¨
txtæ©å±åã 使ç¨js/cjs/mjsæ©å±åå¯è½ä¼ä¸ç°æèµæºæä»¶å²çªï¼ä»è导è´ä»£ç è¿è¡åºéã
webpack.config.js
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
extractComments: {
condition: /^\**!|@preserve|@license|@cc_on/i,
filename: 'extracted-comments.js',
banner: (licenseFile) => {
return `License information can be found in ${licenseFile}`;
},
},
}),
],
},
};bannerç±»åï¼ Boolean|String|Function<(string) -> String>
é»è®¤å¼ï¼ /*! For license information please see ${commentsFile} */
æåå¥ç¦»æä»¶çæ è¯ææ¬å°è¢«æ·»å å°åå§æä»¶çé¡¶é¨ã
å¯ä»¥ä¸º false ï¼æ æ é¢ï¼ï¼ String æä¸ä¸ªå½æ°ï¼Function<(string) -> String> ï¼è¯¥å½æ°å°è¢«ä½¿ç¨åå¨å¥ç¦»ç注éçæä»¶åæ¥è°ç¨ã
æ è¯å
容å°è¢«åå¹¶å°æ³¨éä¸ã
webpack.config.js
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
extractComments: {
condition: true,
filename: (fileData) => {
// The "fileData" argument contains object with "filename", "basename", "query" and "hash"
return `${fileData.filename}.LICENSE.txt${fileData.query}`;
},
banner: (commentsFile) => {
return `My custom banner about license information ${commentsFile}`;
},
},
}),
],
},
};å¥ç¦»ææææç注éï¼å³ /^\**!|@preserve|@license|@cc_on/i ï¼å¹¶ä¿ç /@license/i 注éã
webpack.config.js
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
format: {
comments: /@license/i,
},
},
extractComments: true,
}),
],
},
};妿è¦å¨æå»ºæ¶å»é¤æ³¨éï¼è¯·ä½¿ç¨ä»¥ä¸é ç½®ï¼
webpack.config.js
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
format: {
comments: false,
},
},
extractComments: false,
}),
],
},
};uglify-jsUglifyJS æ¯ä¸æ¬¾é JavaScript è§£æå¨ï¼å缩å¨ï¼ç¾åå¨äºä¸èº«çå·¥å
·éã
webpack.config.js
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
minify: TerserPlugin.uglifyJsMinify,
// `terserOptions` options will be passed to `uglify-js`
// Link to options - https://github.com/mishoo/UglifyJS#minify-options
terserOptions: {},
}),
],
},
};swcswc æ¯ä¸æ¬¾éç¨ rust ç¼åçè¶
å¿«ç¼è¯å¨ï¼å¯ä»¥å°ææ°æ åå TypeScript çè¯æ³çæè¢«å¹¿æ³ä½¿ç¨ç JavaScriptã
â
extractCommentsé项æä¸æ¯æï¼æææ³¨éå°é»è®¤è¢«å é¤ï¼ä¼å¨å°æ¥å¾å°ä¿®å¤ã
webpack.config.js
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
minify: TerserPlugin.swcMinify,
// `terserOptions` options will be passed to `swc` (`@swc/core`)
// Link to options - https://swc.rs/docs/config-js-minify
terserOptions: {},
}),
],
},
};esbuildesbuild æ¯ä¸æ¬¾é常快éç JavaScript æå
å·¥å
·åå缩工å
·ã
â 䏿¯æ
extractCommentséé¡¹ï¼æææ³å¾ç¸å ³ç注éï¼å¦çæï¼è®¸å¯è¯ç)å°è¢«ä¿çã
webpack.config.js
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
minify: TerserPlugin.esbuildMinify,
// `terserOptions` options will be passed to `esbuild`
// Link to options - https://esbuild.github.io/api/#minify
// Note: the `minify` options is true by default (and override other `minify*` options), so if you want to disable the `minifyIdentifiers` option (or other `minify*` options) please use:
// terserOptions: {
// minify: false,
// minifyWhitespace: true,
// minifyIdentifiers: false,
// minifySyntax: true,
// },
terserOptions: {},
}),
],
},
};è¦çé»è®¤ç minify 彿° - ä½¿ç¨ uglify-js è¿è¡å缩ã
webpack.config.js
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
minify: (file, sourceMap) => {
// https://github.com/mishoo/UglifyJS2#minify-options
const uglifyJsOptions = {
/* your `uglify-js` package options */
};
if (sourceMap) {
uglifyJsOptions.sourceMap = {
content: sourceMap,
};
}
return require('uglify-js').minify(file, uglifyJsOptions);
},
}),
],
},
};使ç¨é»è®¤ terser åç¼©å½æ°ï¼
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
compress: true,
},
}),
],
},
};使ç¨å ç½®åç¼©å½æ°ï¼
import type { JsMinifyOptions as SwcOptions } from '@swc/core';
import type { MinifyOptions as UglifyJSOptions } from 'uglify-js';
import type { TransformOptions as EsbuildOptions } from 'esbuild';
import type { MinifyOptions as TerserOptions } from 'terser';
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin<SwcOptions>({
minify: TerserPlugin.swcMinify,
terserOptions: {
// `swc` options
},
}),
new TerserPlugin<UglifyJSOptions>({
minify: TerserPlugin.uglifyJsMinify,
terserOptions: {
// `uglif-js` options
},
}),
new TerserPlugin<EsbuildOptions>({
minify: TerserPlugin.esbuildMinify,
terserOptions: {
// `esbuild` options
},
}),
// Alternative usage:
new TerserPlugin<TerserOptions>({
minify: TerserPlugin.terserMinify,
terserOptions: {
// `terser` options
},
}),
],
},
};请è±ä¸ç¹æ¶é´é 读æä»¬çè´¡ç®æåã