webpack优化相关操作
1、缩小文件搜索的范围
• 优化loader配置
尽量精确使用 include 只命中需要的文件。
module.exports = {
module: {
rules: [
{
// 如果项目源码中只有 js 文件就不要写成 /\.jsx?$/,提升正则表达式性能
test: /\.js$/,
// babel-loader 支持缓存转换出的结果,通过 cacheDirectory 选项开启
use: ['babel-loader?cacheDirectory'],
// 只对项目根目录下的 src 目录中的文件采用 babel-loader
include: path.resolve(__dirname, 'src'),
},
]
},
};
• 优化 resolve.modules 配置
如果能明确第三方模块是在本项目下,那么避免递归向上查询。
module.exports = {
resolve: {
// 使用绝对路径指明第三方模块存放的位置,以减少搜索步骤
// 其中 __dirname 表示当前工作目录,也就是项目根目录
modules: [path.resolve(__dirname, 'node_modules')]
},
};
• 优化 resolve.mainFields 配置
如果能明确第三方入口文件 描述字段,尽可能设置的少,
由于大多数第三方模块都采用 main 字段去描述入口文件的位置,可以这样配置 Webpack:
module.exports = {
resolve: {
// 只采用 main 字段作为入口文件描述字段,以减少搜索步骤
mainFields: ['main'],
},
}
• 优化 resolve.alias 配置
对于一些完整性较强的库采用直接 定义路径 配置。如 react 库,vue库等。
module.exports = {
resolve: {
// 使用 alias 把导入 react 的语句换成直接使用单独完整的 react.min.js 文件,
// 减少耗时的递归解析操作
alias: {
'react': path.resolve(__dirname, './node_modules/react/dist/react.min.js'),
}
},
};
• 优化 resolve.extensions 配置
代码书写时,尽量带上文件后缀。该项列表尽可能短,且高频的放在最前面,不可能的情况不要写。
module.exports = {
resolve: {
// 尽可能的减少后缀尝试的可能性
extensions: ['js'],
},
};
• 优化 module.noParse配置
对没有采用模块化的文件 直接进行忽略设置,如 jQuery 、ChartJS
const path = require('path');
module.exports = {
module: {
// 独完整的 `react.min.js` 文件就没有采用模块化,忽略对 `react.min.js` 文件的递归解析处理
noParse: [/react\.min\.js$/],
},
};
2、使用DLLPlugin插件
使用动态链接库:对于一些大量复用的基础模块,只编译一次,放置到 动态链接库里。常用于包含第三方模块,如 react、react-dom。
涉及问题:
打包成动态链接库;如何使用。
涉及插件:
• DllPlugin 插件:用于打包出一个个单独的动态链接库文件。
• DllReferencePlugin 插件:用于在主要配置文件中去引入 DllPlugin 插件打包好的动态链接库文件
构建:
构建输出的以下这四个文件
├── polyfill.dll.js
├── polyfill.manifest.json
├── react.dll.js
└── react.manifest.json
和以下这一个文件
├── main.js
是由两份不同的构建分别输出的。
动态链接库文件相关的文件需要由一份独立的构建输出,用于给主构建使用。新建一个 Webpack 配置文件 webpack_dll.config.js 专门用于构建它们,文件内容如下:
const path = require('path');
const DllPlugin = require('webpack/lib/DllPlugin');
module.exports = {
// JS 执行入口文件
entry: {
// 把 React 相关模块的放到一个单独的动态链接库
react: ['react', 'react-dom'],
// 把项目需要所有的 polyfill 放到一个单独的动态链接库
polyfill: ['core-js/fn/object/assign', 'core-js/fn/promise', 'whatwg-fetch'],
},
output: {
// 输出的动态链接库的文件名称,[name] 代表当前动态链接库的名称,
// 也就是 entry 中配置的 react 和 polyfill
filename: '[name].dll.js',
// 输出的文件都放到 dist 目录下
path: path.resolve(__dirname, 'dist'),
// 存放动态链接库的全局变量名称,例如对应 react 来说就是 _dll_react
// 之所以在前面加上 _dll_ 是为了防止全局变量冲突
library: '_dll_[name]',
},
plugins: [
// 接入 DllPlugin
new DllPlugin({
// 动态链接库的全局变量名称,需要和 output.library 中保持一致
// 该字段的值也就是输出的 manifest.json 文件 中 name 字段的值
// 例如 react.manifest.json 中就有 "name": "_dll_react"
name: '_dll_[name]',
// 描述动态链接库的 manifest.json 文件输出时的文件名称
path: path.join(__dirname, 'dist', '[name].manifest.json'),
}),
],
};
使用动态链接库文件
构建出的动态链接库文件用于给其它地方使用,在这里也就是给执行入口使用。
用于输出 main.js 的主 Webpack 配置文件内容如下:
const path = require('path');
const DllReferencePlugin = require('webpack/lib/DllReferencePlugin');
module.exports = {
entry: {
// 定义入口 Chunk
main: './main.js'
},
output: {
// 输出文件的名称
filename: '[name].js',
// 输出文件都放到 dist 目录下
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
// 项目源码使用了 ES6 和 JSX 语法,需要使用 babel-loader 转换
test: /\.js$/,
use: ['babel-loader'],
exclude: path.resolve(__dirname, 'node_modules'),
},
]
},
plugins: [
// 告诉 Webpack 使用了哪些动态链接库
new DllReferencePlugin({
// 描述 react 动态链接库的文件内容
manifest: require('./dist/react.manifest.json'),
}),
new DllReferencePlugin({
// 描述 polyfill 动态链接库的文件内容
manifest: require('./dist/polyfill.manifest.json'),
}),
],
devtool: 'source-map'
};
注意:在 webpack_dll.config.js 文件中,DllPlugin 中的 name 参数必须和 output.library 中保持一致。 原因在于 DllPlugin 中的 name 参数会影响输出的 manifest.json 文件中 name 字段的值, 而在 webpack.config.js 文件中 DllReferencePlugin 会去 manifest.json 文件读取 name 字段的值, 把值的内容作为在从全局变量中获取动态链接库中内容时的全局变量名。
执行构建
在修改好以上两个 Webpack 配置文件后,需要重新执行构建。 重新执行构建时要注意的是需要先把动态链接库相关的文件编译出来,因为主 Webpack 配置文件中定义的 DllReferencePlugin 依赖这些文件。
执行构建时流程如下:
如果动态链接库相关的文件还没有编译出来,就需要先把它们编译出来。方法是执行 webpack --config webpack_dll.config.js 命令。
在确保动态链接库存在时,才能正常的编译出入口执行文件。方法是执行 webpack 命令。这时你会发现构建速度有了非常大的提升。
3、happyPack 插件
使用多进程 进行文件转换操作,提高转换效率。
场景:
文件特别多,时长不能忍时,尝试。普通项目效果不明显。
涉及插件:
HappyPack。
npm i -D happypack
分解工作 和 管理工作由插件负责
实例:
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HappyPack = require('happypack');
module.exports = {
module: {
rules: [
{
test: /\.js$/,
// 把对 .js 文件的处理转交给 id 为 babel 的 HappyPack 实例
use: ['happypack/loader?id=babel'],
// 排除 node_modules 目录下的文件,node_modules 目录下的文件都是采用的 ES5 语法,没必要再通过 Babel 去转换
exclude: path.resolve(__dirname, 'node_modules'),
},
{
// 把对 .css 文件的处理转交给 id 为 css 的 HappyPack 实例
test: /\.css$/,
use: ExtractTextPlugin.extract({
use: ['happypack/loader?id=css'],
}),
},
]
},
plugins: [
new HappyPack({
// 用唯一的标识符 id 来代表当前的 HappyPack 是用来处理一类特定的文件
id: 'babel',
// 如何处理 .js 文件,用法和 Loader 配置中一样
loaders: ['babel-loader?cacheDirectory'],
// ... 其它配置项
}),
new HappyPack({
id: 'css',
// 如何处理 .css 文件,用法和 Loader 配置中一样
loaders: ['css-loader'],
}),
new ExtractTextPlugin({
filename: `[name].css`,
}),
],
};
以上代码有两点重要的修改:
• 在 Loader 配置中,所有文件的处理都交给了 happypack/loader 去处理,使用紧跟其后的 querystring ?id=babel 去告诉 happypack/loader 去选择哪个 HappyPack 实例去处理文件。
• 在 Plugin 配置中,新增了两个 HappyPack 实例分别用于告诉 happypack/loader 去如何处理 .js 和 .css 文件。选项中的 id 属性的值和上面 querystring 中的 ?id=babel 相对应,选项中的 loaders 属性和 Loader 配置中一样。
在实例化 HappyPack 插件的时候,除了可以传入 id 和 loaders 两个参数外,HappyPack 还支持如下参数:
• threads 代表开启几个子进程去处理这一类型的文件,默认是3个,类型必须是整数。
• verbose 是否允许 HappyPack 输出日志,默认是 true。
• threadPool 代表共享进程池,即多个 HappyPack 实例都使用同一个共享进程池中的子进程去处理任务,以防止资源占用过多,相关代码如下:
const HappyPack = require('happypack');
// 构造出共享进程池,进程池中包含5个子进程
const happyThreadPool = HappyPack.ThreadPool({ size: 5 });
module.exports = {
plugins: [
new HappyPack({
// 用唯一的标识符 id 来代表当前的 HappyPack 是用来处理一类特定的文件
id: 'babel',
// 如何处理 .js 文件,用法和 Loader 配置中一样
loaders: ['babel-loader?cacheDirectory'],
// 使用共享进程池中的子进程去处理任务
threadPool: happyThreadPool,
}),
new HappyPack({
id: 'css',
// 如何处理 .css 文件,用法和 Loader 配置中一样
loaders: ['css-loader'],
// 使用共享进程池中的子进程去处理任务
threadPool: happyThreadPool,
}),
new ExtractTextPlugin({
filename: `[name].css`,
}),
],
};
4、使用 parallelUglifyPlugin
多进程 进行文件混淆压缩。每个子进程还是通过内置的UglifyJS 去压缩代码。
场景:
普通可用,有提升。
涉及插件:
npm i -D webpack-parallel-uglify-plugin
实例:
const path = require('path');
const DefinePlugin = require('webpack/lib/DefinePlugin');
const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
module.exports = {
plugins: [
// 使用 ParallelUglifyPlugin 并行压缩输出的 JS 代码
new ParallelUglifyPlugin({
// 传递给 UglifyJS 的参数
uglifyJS: {
output: {
// 最紧凑的输出
beautify: false,
// 删除所有的注释
comments: false,
},
compress: {
// 在UglifyJs删除没有用到的代码时不输出警告
warnings: false,
// 删除所有的 `console` 语句,可以兼容ie浏览器
drop_console: true,
// 内嵌定义了但是只用到一次的变量
collapse_vars: true,
// 提取出出现多次但是没有定义成变量去引用的静态值
reduce_vars: true,
}
},
}),
],
};
在通过 new ParallelUglifyPlugin() 实例化时,支持以下参数:
• test:使用正则去匹配哪些文件需要被 ParallelUglifyPlugin 压缩,默认是 /.js$/,也就是默认压缩所有的 .js 文件。
• include:使用正则去命中需要被 ParallelUglifyPlugin 压缩的文件。默认为 []。
• exclude:使用正则去命中不需要被 ParallelUglifyPlugin 压缩的文件。默认为 []。
• cacheDir:缓存压缩后的结果,下次遇到一样的输入时直接从缓存中获取压缩后的结果并返回。cacheDir 用于配置缓存存放的目录路径。默认不会缓存,想开启缓存请设置一个目录路径。
• workerCount:开启几个子进程去并发的执行压缩。默认是当前运行电脑的 CPU 核数减去1。
• sourceMap:是否输出 Source Map,这会导致压缩过程变慢。
• uglifyJS:用于压缩 ES5 代码时的配置,Object 类型,直接透传给 UglifyJS 的参数。
• uglifyES:用于压缩 ES6 代码时的配置,Object 类型,直接透传给 UglifyES 的参数
5、区分环境
process.env.NODE_ENV !== 'production' 中的 NODE_ENV 和 'production' 两个值是社区的约定,通常使用这条判断语句在区分开发环境和线上环境。
6、压缩代码
压缩js:
最优配置如下(1版本可用)
const UglifyJSPlugin = require('webpack/lib/optimize/UglifyJsPlugin');
module.exports = {
plugins: [
// 压缩输出的 JS 代码
new UglifyJSPlugin({
compress: {
// 在UglifyJs删除没有用到的代码时不输出警告
warnings: false,
// 删除所有的 `console` 语句,可以兼容ie浏览器
drop_console: true,
// 内嵌定义了但是只用到一次的变量
collapse_vars: true,
// 提取出出现多次但是没有定义成变量去引用的静态值
reduce_vars: true,
},
output: {
// 最紧凑的输出
beautify: false,
// 删除所有的注释
comments: false,
}
}),
],
};
注意事项:
uglifyjsplugin 插件版本不一致,可能配置项也不一样,注意区分。目前有1和2。vue-cli 目前依赖的是 1 版本。
压缩ES6:
npm i -D uglifyjs-webpack-plugin@beta
场景:
支持es6环境的系统。如最新版Chrome等。暂时用处不大。
const UglifyESPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
plugins: [
new UglifyESPlugin({
// 多嵌套了一层
uglifyOptions: {
compress: {
// 在UglifyJs删除没有用到的代码时不输出警告
warnings: false,
// 删除所有的 `console` 语句,可以兼容ie浏览器
drop_console: true,
// 内嵌定义了但是只用到一次的变量
collapse_vars: true,
// 提取出出现多次但是没有定义成变量去引用的静态值
reduce_vars: true,
},
output: {
// 最紧凑的输出
beautify: false,
// 删除所有的注释
comments: false,
}
}
})
]
}
压缩css:
css-loader 选项 minimize 支持压缩。可用性 待测试
use: ['css-loader?minimize']
7、Tree Shaking
去除无用代码(没有用到的)。得是 基于es6模块化规范的,才会被摇除。
举例:
配置:
1、关闭es6 模块转换功能,保留es6 语法。此时用不到 es6 转换器。
{
"presets": [
[
"env",
{
"modules": false
}
]
]
}
2、使用uglifyPlugin 插件来压缩,或者 启动 Webpack 时带上 --optimize-minimize 参数
8、提取公共代码
使用场景:
多个页面时,每个页面都是一个独立的单页应用。会有很多相同资源 被重复加载。
如何提取:
1、多页面使用的技术栈一致的,此时将 基础库和 基础样式提取 作为基础库文件:base.js。
以react 举例,所有页面会依赖 react、react-dom等库。
2、与业务相关的 通用js 可提取到 业务基础文件:common.js。
场景:
作为基础库文件,基本不会变动;业务基础文件 可能变动性稍微大一些,做到了 最优缓存。
webpck实现
所用插件:
CommonsChunkPlugin webpack4 里用他俩替代
optimization.splitChunks and optimization.runtimeChunk)
来自 <https://blog.csdn.net/VhWfR2u02Q/article/details/79969250>
示例-common提取:
const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin');
new CommonsChunkPlugin({
// 从哪些 Chunk 中提取
chunks: ['a', 'b'],
// 提取出的公共部分形成一个新的 Chunk,这个新 Chunk 的名称
name: 'common'
})
示例-base提取:
base.js
// 所有页面都依赖的基础库
import 'react';
import 'react-dom';
// 所有页面都使用的样式
import './base.css';
base配置
module.exports = {
entry: {
base: './base.js'
},
};
从common中提取base
new CommonsChunkPlugin({
// 从 common 和 base 两个现成的 Chunk 中提取公共的部分
chunks: ['common', 'base'],
// 把公共的部分放到 base 中
name: 'base'
})
示例-引用:
<script src="base.js"></script>
<script src="common.js"></script>
<script src="a.js"></script>
其他情形:
除了基础库 内容,一些常用内容提取到 common.js 里。用到了 插件选项
minChunks:指定的代码块中出现的最小次数。
假如 minChunks=2、chunks=['a','b','c','d'],任何一个文件只要在 ['a','b','c','d'] 中任意两个以上的 Chunk 中都出现过,这个文件就会被提取出来
9、按需加载
支持异步加载。
10、prepack
求值器,编译时 提前将结果就编译进代码里,而不是 运行时才求值。
涉及插件:
prepack-webpack-plugin 目前只能运行在 webpack 4.0之上
11、scope hoisiting 作用域提升
文件内容合并,压缩 优化。仅用于 es6 语法。
涉及插件:
webpack.optimize.ModuleConcatenationPlugin
最优配置:
module.exports = {
resolve: {
// 针对 Npm 中的第三方模块优先采用 jsnext:main 中指向的 ES6 模块化语法的文件
mainFields: ['jsnext:main', 'browser', 'main']
},
plugins: [
// 开启 Scope Hoisting
new ModuleConcatenationPlugin(),
],
};
12、输出分析用以 特定优化
使用命令:
webpack --profile --json > stats.json
会在项目下生成 stats.json文件,里面包含了所有的 输出信息。
可视化工具:
1、在线可视,非常全。 http://webpack.github.io/analyse/
2、插件 webpack-bundle-analyzer;全局安装,使用:先生成 stats.json文件,然后在项目下使用命令webpack-bundle-analyzer stats.json
13、优化总结
侧重优化开发体验的配置文件 webpack.config.js:
const path = require('path');
const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin');
const {AutoWebPlugin} = require('web-webpack-plugin');
const HappyPack = require('happypack');
// 自动寻找 pages 目录下的所有目录,把每一个目录看成一个单页应用
const autoWebPlugin = new AutoWebPlugin('./src/pages', {
// HTML 模版文件所在的文件路径
template: './template.html',
// 提取出所有页面公共的代码
commonsChunk: {
// 提取出公共代码 Chunk 的名称
name: 'common',
},
});
module.exports = {
// AutoWebPlugin 会找为寻找到的所有单页应用,生成对应的入口配置,
// autoWebPlugin.entry 方法可以获取到生成入口配置
entry: autoWebPlugin.entry({
// 这里可以加入你额外需要的 Chunk 入口
base: './src/base.js',
}),
output: {
filename: '[name].js',
},
resolve: {
// 使用绝对路径指明第三方模块存放的位置,以减少搜索步骤
// 其中 __dirname 表示当前工作目录,也就是项目根目录
modules: [path.resolve(__dirname, 'node_modules')],
// 针对 Npm 中的第三方模块优先采用 jsnext:main 中指向的 ES6 模块化语法的文件,使用 Tree Shaking 优化
// 只采用 main 字段作为入口文件描述字段,以减少搜索步骤
mainFields: ['jsnext:main', 'main'],
},
module: {
rules: [
{
// 如果项目源码中只有 js 文件就不要写成 /\.jsx?$/,提升正则表达式性能
test: /\.js$/,
// 使用 HappyPack 加速构建
use: ['happypack/loader?id=babel'],
// 只对项目根目录下的 src 目录中的文件采用 babel-loader
include: path.resolve(__dirname, 'src'),
},
{
test: /\.js$/,
use: ['happypack/loader?id=ui-component'],
include: path.resolve(__dirname, 'src'),
},
{
// 增加对 CSS 文件的支持
test: /\.css$/,
use: ['happypack/loader?id=css'],
},
]
},
plugins: [
autoWebPlugin,
// 使用 HappyPack 加速构建
new HappyPack({
id: 'babel',
// babel-loader 支持缓存转换出的结果,通过 cacheDirectory 选项开启
loaders: ['babel-loader?cacheDirectory'],
}),
new HappyPack({
// UI 组件加载拆分
id: 'ui-component',
loaders: [{
loader: 'ui-component-loader',
options: {
lib: 'antd',
style: 'style/index.css',
camel2: '-'
}
}],
}),
new HappyPack({
id: 'css',
// 如何处理 .css 文件,用法和 Loader 配置中一样
loaders: ['style-loader', 'css-loader'],
}),
// 4-11提取公共代码
new CommonsChunkPlugin({
// 从 common 和 base 两个现成的 Chunk 中提取公共的部分
chunks: ['common', 'base'],
// 把公共的部分放到 base 中
name: 'base'
}),
],
watchOptions: {
// 4-5使用自动刷新:不监听的 node_modules 目录下的文件
ignored: /node_modules/,
}
};
侧重优化输出质量的配置文件 webpack-dist.config.js:
const path = require('path');
const DefinePlugin = require('webpack/lib/DefinePlugin');
const ModuleConcatenationPlugin = require('webpack/lib/optimize/ModuleConcatenationPlugin');
const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const {AutoWebPlugin} = require('web-webpack-plugin');
const HappyPack = require('happypack');
const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
// 自动寻找 pages 目录下的所有目录,把每一个目录看成一个单页应用
const autoWebPlugin = new AutoWebPlugin('./src/pages', {
// HTML 模版文件所在的文件路径
template: './template.html',
// 提取出所有页面公共的代码
commonsChunk: {
// 提取出公共代码 Chunk 的名称
name: 'common',
},
// 指定存放 CSS 文件的 CDN 目录 URL
stylePublicPath: '//css.cdn.com/id/',
});
module.exports = {
// AutoWebPlugin 会找为寻找到的所有单页应用,生成对应的入口配置,
// autoWebPlugin.entry 方法可以获取到生成入口配置
entry: autoWebPlugin.entry({
// 这里可以加入你额外需要的 Chunk 入口
base: './src/base.js',
}),
output: {
// 给输出的文件名称加上 Hash 值
filename: '[name]_[chunkhash:8].js',
path: path.resolve(__dirname, './dist'),
// 指定存放 JavaScript 文件的 CDN 目录 URL
publicPath: '//js.cdn.com/id/',
},
resolve: {
// 使用绝对路径指明第三方模块存放的位置,以减少搜索步骤
// 其中 __dirname 表示当前工作目录,也就是项目根目录
modules: [path.resolve(__dirname, 'node_modules')],
// 只采用 main 字段作为入口文件描述字段,以减少搜索步骤
mainFields: ['jsnext:main', 'main'],
},
module: {
rules: [
{
// 如果项目源码中只有 js 文件就不要写成 /\.jsx?$/,提升正则表达式性能
test: /\.js$/,
// 使用 HappyPack 加速构建
use: ['happypack/loader?id=babel'],
// 只对项目根目录下的 src 目录中的文件采用 babel-loader
include: path.resolve(__dirname, 'src'),
},
{
test: /\.js$/,
use: ['happypack/loader?id=ui-component'],
include: path.resolve(__dirname, 'src'),
},
{
// 增加对 CSS 文件的支持
test: /\.css$/,
// 提取出 Chunk 中的 CSS 代码到单独的文件中
use: ExtractTextPlugin.extract({
use: ['happypack/loader?id=css'],
// 指定存放 CSS 中导入的资源(例如图片)的 CDN 目录 URL
publicPath: '//img.cdn.com/id/'
}),
},
]
},
plugins: [
autoWebPlugin,
// 4-14开启ScopeHoisting
new ModuleConcatenationPlugin(),
// 4-3使用HappyPack
new HappyPack({
// 用唯一的标识符 id 来代表当前的 HappyPack 是用来处理一类特定的文件
id: 'babel',
// babel-loader 支持缓存转换出的结果,通过 cacheDirectory 选项开启
loaders: ['babel-loader?cacheDirectory'],
}),
new HappyPack({
// UI 组件加载拆分
id: 'ui-component',
loaders: [{
loader: 'ui-component-loader',
options: {
lib: 'antd',
style: 'style/index.css',
camel2: '-'
}
}],
}),
new HappyPack({
id: 'css',
// 如何处理 .css 文件,用法和 Loader 配置中一样
// 通过 minimize 选项压缩 CSS 代码
loaders: ['css-loader?minimize'],
}),
new ExtractTextPlugin({
// 给输出的 CSS 文件名称加上 Hash 值
filename: `[name]_[contenthash:].css`,
}),
// 4-11提取公共代码
new CommonsChunkPlugin({
// 从 common 和 base 两个现成的 Chunk 中提取公共的部分
chunks: ['common', 'base'],
// 把公共的部分放到 base 中
name: 'base'
}),
new DefinePlugin({
// 定义 NODE_ENV 环境变量为 production 去除 react 代码中的开发时才需要的部分
'process.env': {
NODE_ENV: JSON.stringify('production')
}
}),
// 使用 ParallelUglifyPlugin 并行压缩输出的 JS 代码
new ParallelUglifyPlugin({
// 传递给 UglifyJS 的参数
uglifyJS: {
output: {
// 最紧凑的输出
beautify: false,
// 删除所有的注释
comments: false,
},
compress: {
// 在UglifyJs删除没有用到的代码时不输出警告
warnings: false,
// 删除所有的 `console` 语句,可以兼容ie浏览器
drop_console: true,
// 内嵌定义了但是只用到一次的变量
collapse_vars: true,
// 提取出出现多次但是没有定义成变量去引用的静态值
reduce_vars: true,
}
},
}),
]
};
webpack优化相关操作的更多相关文章
- 浅探webpack优化
由于前端的快速发展,相关工具的发展速度也是相当迅猛,各大框架例如vue,react都有自己优秀的脚手架工具来帮助我们快速启动一个新项目,也正式因为这个原因,我们对于脚手架中最关键的一环webpack相 ...
- js DOM优化相关探索
我在这尝试两个方面:-->DOM与js -->DOM与浏览器 (最近在秒味视频上学到不少,哈哈哈) 一.DOM与js 1.js与dom的交互问题 频繁的与dom交互,是一件浪费时间与金钱的 ...
- Mysql优化相关总结
Mysql优化相关总结 2016-05-31 数据库集中营 优化顺序: 选择适当的引擎和表结构和数据类型 建立索引,优化sql. 增加缓存,redis.memcache. 主从.主主,读写分离. my ...
- 从零自学Hadoop(24):Impala相关操作上
阅读目录 序 数据库相关 表相关 系列索引 本文版权归mephisto和博客园共有,欢迎转载,但须保留此段声明,并给出原文链接,谢谢合作. 文章是哥(mephisto)写的,SourceLink 序 ...
- webpack优化之code splitting
作为当前风头正盛的打包工具,webpack风靡前端界.确实作为引领了一个时代的打包工具,很多方面都带来了颠覆性的改进,让我们更加的感受到自动化的快感.不过最为大家诟病的一点就是用起来太难了. 要想愉快 ...
- LayUI之table数据表格获取行、行高亮等相关操作
前言 目前LayUI数据表格既美观有不乏一些实用功能.基本上表格应有的操作已经具备,LayUI作者[贤心]肯定是煞费苦心去优化,此处致敬.但是实话实话,如果单纯那数据表格功能来说,EasUI的数据表格 ...
- Django框架详细介绍---ORM相关操作
Django ORM相关操作 官方文档: https://docs.djangoproject.com/en/2.0/ref/models/querysets/ 1.必须掌握的十三个方法 <1& ...
- Django ORM那些相关操作zi
Django ORM那些相关操作 一般操作 看专业的官网文档,做专业的程序员! 必知必会13条 <1> all(): 查询所有结果 <2> filter(**kwargs) ...
- 浅谈webpack优化
webpack优化方案 1. 优化开发体验 1-1. 加快构建速度 ① 缩小文件搜索范围 由于 Loader 对文件的转换操作很耗时,需要让尽可能少的文件被 Loader 处理,用include和ex ...
随机推荐
- BTrace 问题辅助排查工具使用手册
BTrace是调试神器,可以通过自己编写的脚本,获取应用的一切调用信息.而不需要重启应用! Btrace 项目源码信息(你行你上~) 项目地址:http://github.com/btraceio/b ...
- 从一张图开始,谈一谈.NET Core和前后端技术的演进之路
从一张图开始,谈一谈.NET Core和前后端技术的演进之路 邹溪源,李文强,来自长沙.NET技术社区 一张图 2019年3月10日,在长沙.NET 技术社区组织的技术沙龙<.NET Core和 ...
- jdk各个版本的新特性(jdk1.7,1.8,1.9)
用了这么久的jdk,应该会有很多人和我一样,不知道各个版本的jdk的一些新特性,这里简单总结一下.. jdk1.7新特性: 1.在Switch中可以用String字符串 2.对Java集合(Colle ...
- 学习Identity Server 4的预备知识 (误删, 重补)
我要使用asp.net core 2.0 web api 搭建一个基础框架并立即应用于一个实际的项目中去. 这里需要使用identity server 4 做单点登陆. 下面就简单学习一下相关的预备知 ...
- 死磕 java集合之ConcurrentHashMap源码分析(三)
本章接着上两章,链接直达: 死磕 java集合之ConcurrentHashMap源码分析(一) 死磕 java集合之ConcurrentHashMap源码分析(二) 删除元素 删除元素跟添加元素一样 ...
- 【Android Studio安装部署系列】十二、Android studio代码混淆
版权声明:本文为HaiyuKing原创文章,转载请注明出处! 概述 为什么需要代码混淆呢?原因很简单,你的apk很容易被反编译出来,你写的代码都会被看到,因此我们需要在编译过程中对代码进行一定程度的混 ...
- 【Android Studio安装部署系列】三十、从Android studio2.2.2升级到Android studio3.0之路
版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 Android Studio 3.0的新功能 https://mp.weixin.qq.com/s/2XmVG4mKEDX6-bvZ ...
- 『集群』003 Slithice 最简分布式(多个客户端,一个独立服务端)
Slithice 最简分布式(多个客户端,一个独立服务端) 案例Demo 展示: 我们搭建一个 可以 独立运行 的 服务端:然后 多个客户端 并发链接 这个 服务端 完成 分布式逻辑: 服务器 独立运 ...
- Maven-常用插件
罗列笔者认为比较有用的一些maven打包插件,方便后续查阅 spring-boot-maven-plugin springboot自带的maven插件,可用于简单的JAR/WAR方式打包,官方地址为h ...
- jq切换面板
<!DOCTYPE html> <html lang="en" xmlns="http://www.w3.org/1999/xhtml"> ...