webpack是一个JavaScript应用程序的静态模块打包器。下面从为什么、干了啥来说说我对它的理解。
为什么要使用webpack打包?
将ES6、ES7语法转换成浏览器支持的语法、生成CSS3前缀、代码压缩、编译less sass、编译jsx vuex、处理图片等。
webpack基本配置
创建一个webpack.config.js文件,以下是一个react工程项目的基本配置
const path = require('path');
module.exports = {
mode: "development"
entry: {
inde: './src/index.js'
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
}, {
test: /\.less$/,
use:["style-loader","css-loader","less-loader"]
// 加载时顺序从右向左
},
{
test: /\.(png|svg|jpg|gif)$/,
use: ['file-loader']
},
{
test: /\.(js|jsx)$/,
loader: 'babel-loader',
exclude: /node_modules/
}]
},
devServer: {
contentBase: './dist',
hot: true
},
plugins: [
new CleanWebpackPlugin(),//每次编译都会把dist下的文件清除,我们可以在合适的时候打开这行代码,例如我们打包的时候,开发过程中这段代码关闭比较好
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({
template: 'src/index.html' //使用一个模板
}),
]
}
然后在webpack.json的script中配置start build命令,现在就可以打包了。目前打包时间是27s
"start": "webpack-dev-server --open",
"build": "webpack"
随着项目代码越来越多,开启项目服务和打包会越来越慢,这里就需要对配置进行优化,下面来说说我优化一个前年的老项目,打包时间从27s到4.5s
第一步:多进程多实例打包,我采用的是对所有项目都比较友好的happypack插件,其实还有thread-loader和parallel-webpack,但是当前的项目不太合适使用后2个插件,后续我会补充这2个插件的效果。
const HappyPack = require('happypack');
// loader部分
// 在loader的babel前加上happypack/,后加上?id=jsx
{ test: /\.(js|jsx)$/, exclude: /node_modules/, loader: 'happypack/babel?id=jsx' },
// plugins部分
// 将babel-loader编译的过程放进多进程处理中,其实还可以处理css-loader和file-loader,这里就不写了
// id对应的是loader部分的?id=jsx,loader对应的是babel全称babel-loader
new HappyPack({
id: 'jsx',
loaders: [ 'babel-loader' ]
}),
添加了多进程打包后,打包时间缩短到10s
打包时间减少了17s,非常惊人,但是我们还可以再减少打包时间,往下看:
webpack-parallel-uglify-plugin
这个插件可以帮助有很多入口点的项目加速他们的构建。webpack提供的UglifyJS插件在每个输出文件上依次运行。这个插件运行uglify与一个线程并行为每个可用的cpu。这可以显著减少构建时间,因为小型化非常耗费CPU资源
const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
new ParallelUglifyPlugin({
uglifyJS: {
output: {
beautify: false,
comments: false,
},
compress: {
warnings: false,
drop_console: true,
collapse_vars: true,
reduce_vars: true,
}
}
}),
现在打包时间只要8s了,这里还没有结束...
html-webpack-externals-plugin
像react,react-dom等等依赖包比较大,我们可以引用cdn的资源,不用本地编译,在插件中配置他们的cdn地址,最后html文件中就会以script标签引用这些依赖
const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin')
new HtmlWebpackExternalsPlugin({
externals: [
{
module: 'react',
entry: 'https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react.min.js',
global: 'react',
},
{
module: 'react-dom',
entry: 'https://cdn.bootcss.com/react-dom/15.3.1/react-dom.js',
global: 'react-dom',
},
{
module: 'moment',
entry: 'https://cdn.bootcss.com/moment.js/2.22.1/moment.js',
global: 'moment'
}
]
}),
打包后的html文件
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react.min.js"></script>
<script type="text/javascript" src="https://cdn.bootcss.com/react-dom/15.3.1/react-dom.js"></script>
<script type="text/javascript" src="https://cdn.bootcss.com/moment.js/2.22.1/moment.js"></script>
<script type="text/javascript" src="/myAccount/js/vendor.e4c0ae97.js"></script></body>
现在打包时间是6s了,最后再加个dll,看看
创建一个webpack.dll.config.js文件,配置如下:
const path = require("path");
const webpack = require("webpack");
const {
BundleAnalyzerPlugin
} = require('webpack-bundle-analyzer')
const vendor = [
"react",
"react-dom",
"react-router-dom",
"jquery",
"js-md5",
"moment",
"react-router",
"react-weui",
"weui",
"redux",
"immutable",
];
const dllPath = path.join(__dirname, 'dll');
module.exports = {
entry: {
dll: vendor
},
output: {
path: dllPath,
filename: "[name].js",
library: "_dll_[name]"
},
plugins: [
new webpack.DllPlugin({
name: "_dll_[name]",
path: path.join(__dirname, 'dll','manifest.json'),
}),
new BundleAnalyzerPlugin({
analyzerMode: 'static'
}),
]
}
在webpack.config.js中通过webpack.DllReferencePlugin引用,配置如下:
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./dll/manifest.json')
}),
又减少了1s webpack里面有个modules配置,"modules": false时,就是没有引用的部分不会打包进去,比如a.js中有10个函数,b.js只引用了a.js中的2个方法,另外8个方法就不会打包了。在.babelrc中配置"modules": false
{
"presets": ["react", "es2015"],
"env": {
"dev": {
"plugins": [["react-transform", {
"transforms": [{
"transform": "react-transform-hmr",
"imports": ["react"],
"locals": ["module"]
}]
}]]
}
},
"modules": false
}
简直是惊呆了,现在打包时间只要4s了。