webpack通过配置loader和plugin可以帮我们做很多不同的工作,但是比较头疼的是,记住很多的loader和plugin并不方便,所以webpack4之后就引入了新的概念,就是mode模式,通过配置官网约定的两个模式:开发模式和生产模式,这两个模式分别有默认配置好的插件供我们使用,我们不需要再为配置而发愁(convention over configuration也就是约定大于配置),如果模式中有些细微的东西在项目中不太合适,也可以overwrite重写里面的配置,但我们不需要大规模的从头到尾自己来写配置文件。
Tree-shaking
Tree-shaking用来减少打包后资源的体积,有些代码在生产中是用不到的,我们在打包时就会shaking掉,要使用Tree-shaking代码无论是自己写的还是第三方引入的,它们都必须是模块化的,也就是有导入和导出。
- 上下文未用到的代码(dead code)
- 基于ES6 import export
有时候我们的代码中会修改全局作用域,在全局中添加的方法和属性是无法体现export是体现不出来的,所以在shaking中会被摇掉那程序运行就会出现问题,此时我们可以告诉webpack Tree-shaking不需要处理的文件,在package.json文件中配置相关的js,这里只是列出了css(css不是模块化编写的):
"sideEffects":[
"*.css"
]
babel相关配置
一款可以将 ES6 代码转换为 ES5 代码的转译器。
babel.config.js:
module.exports = {
presets: [
[
'@babel/preset-env',
{
modules: false,
"targets": {
"browsers": [">0.25%"]
},
"useBuiltIns": "usage",
"bugfixes": true
}
],
'@babel/preset-react'
],
plugins: [
'@babel/plugin-proposal-class-properties',
"@babel/plugin-transform-runtime",
]
};
preset-env在转码的时候会把es6模块化的语法转成其它模块化的语法,但在项目中我们希望保留es6模块化的语法,所以 配置modules: false,
,告诉babel不需要转成其它模块化的语法,这样tree-shaking才能起到作用。
作用域提升
比如下面代码的依赖关系:
作用域提升可以把代码尽量做一个合并,这样可以减小代码体积,执行效率也会更高,这里要注意babel的modules:false
的配置,因为所有的这些也是要基于es6的import,export的语法,在生产模式中webpack会自动帮我们做一个作用域提升。
提速webpack打包过程
noParse
noParse(不解析)提高构建速度,直接告诉webpack不进行解析的库(比如第三方的类库,工具类库等本身比较大的库,使用比较传统的非模块化方式的类库),被忽略的不进行解析的库不能有import、require、define的引入方式,比如下面的lodash库,我们不需要对它进行递归的解析:
DllPlugin
DllPlugin可以避免打包时对不变的库重复构建,比如我们的项目是用react,react-dom写的,react,react-dom在我们整个项目的生命周期中几乎不做改动,所以在构建的过程中不需要重复的去构建,如果把它们提取出来像动态链接库一样引用,这样可以大大提高构建速度。
webpack.dll.config.js:
const path = require("path");
const webpack = require("webpack");
module.exports = {
mode: "production",
entry: {
react: ["react", "react-dom"],
},
output: {
filename: "[name].dll.js",
path: path.resolve(__dirname, "dll"),
library: "[name]"
},
plugins: [
new webpack.DllPlugin({
name: "[name]",
path: path.resolve(__dirname, "dll/[name].manifest.json")
})
]
};
package.json中的script增加一项配置"dll-start":"NODE=ENV=production webpack --config webpack.dll.config.js",
:
"scripts": {
"build": "cross-env NODE_ENV=production webpack",
"start": "npm run build && node server.js",
"dll-start":"NODE=ENV=production webpack --config webpack.dll.config.js",
"dev": "webpack-dev-server"
},
运行npm run dll-build
如果报错*‘NODE_ENV’ 不是内部或外部命令,也不是可运行的程序或批处理文件。*
改成"dll-start":"cross-env NODE=ENV=production webpack --config webpack.dll.config.js",
会生成两个文件:
这样把react和react-dom全都打包到dll目录中,将它们变成动态链接的文件,同时这里还会生成一个描述文件react.manifest.json
,
接着在webpack.config.js
文件中把这个描述文件添加进去,这样才能对webpack的正常打包的过程进行优化,DllReferencePlugin
插件是webpack中对dll文件进行引用的插件,这里其实是间接引用的,我们直接引用的是生成的react
相关的描述文件,这个描述文件会告诉webpack在构建过程中中找到react的dll链接文件。运行npm run build
在做动态链接之后,打包时间是2383ms。
在做动态链接之前,打包时间是2607ms。
可以多取几次值,平均值来对比,效果还是比较明显的。
如果有其它的库像react
,react-dom
一样比较稳定,都可以像这样提高构建速度,DllPlugin
可以避免打包时对不变额库重复构建,但我们在生产环境中用的比较少,生产不会经常去打包,在开发中用这个插件更合适,生产环境中会用到热部署,为了加快开发使用DllPlugin
会大大提高我们的开发效率。