Mode 用来指定当前的构建环境是:production、development、还是none。设置 mode 可以使用 webpack 的内置函数,默认值是 production。
mode 的内置函数功能如下:
模式(mode):提供 mode 配置选项,告知 webpack 使用相应模式的内置优化。
用法:只在配置中提供 mode 选项:
module.exports = {
mode: 'production'
};
或者从 CLI 参数中传递:
webpack --mode=production
一、mode取值
1、development:会将 process.env.NODE_ENV 的值设为 development。启用 NamedChunksPlugin 和 NamedModulesPlugin。
// webpack.development.config.js
module.exports = {
+ mode: 'development'
- plugins: [
- new webpack.NamedModulesPlugin(),
- new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("development") }),
- ]
}
2、production:会将 process.env.NODE_ENV 的值设为 production。启用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin 和 UglifyJsPlugin。
// webpack.production.config.js
module.exports = {
+ mode: 'production',
- plugins: [
- new UglifyJsPlugin(/* ... */),
- new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") }),
- new webpack.optimize.ModuleConcatenationPlugin(),
- new webpack.NoEmitOnErrorsPlugin()
- ]
}
production模式下会启用UglifyJsPlugin插件(移除未使用的内容和文件压缩)
二、mode取值的区别
分别用 production 和 development 打包,编译的区别如下:
1、development打包后,一些没有依赖的方法、变量、文件会保留;而 production 则会移除。
2、production 打包后,代码会进行压缩,比 development 的文件小。
三、mode不同值的打包
1、none模式下的模块打包
在没有任何优化处理的情况下,按照webpack默认的情况下打包出模块,它会将模块打包至数组之中,调用模块的时候,就是直接调用模块在此数组中的一个序号,然后没有进行压缩、混淆之类的优化。
但是无论是在开发环境development下,还是在正式环境production下,这个代码都是不过关的。对于开发环境,此代码可读性太差,对于正式环境,此代码不够简洁。因此为了减少一次重复操作,webpack4提供的development/production可以很大程度上帮我们做一大部分的事情,我们要做的,就是在这些事的基础上增加功能。
2、development模式下,webpack做了哪些打包工作
development是告诉程序,我现在是开发状态,也就是打包出来的内容要对开发友好。在此mode下,就做了以下插件的事情,其他什么都没有做,所以这些插件可以省略。
//webpack.config.js
module.exports = {
mode:'development',
devtool:'eval',
plugins: [
new webpack.NamedModulesPlugin(),
new webpack.NamedChunksPlugin(),
new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("development") })
]
}
我们看看NamedModulesPlugin和NamedChunksPlugin这两个插件都做了啥,原本我们的webpack并不会给打包的模块加上名字,一般都是按照序号来,从0开始,然后加载第几个模块,这个对机器来说无所谓,查找载入很快,但是对于人脑来说就是灾难了,所以这个时候给各个模块加上姓名,便于开发的时候查找。
没有NamedModulesPlugin,模块就是一个数组,引用也是按照在数组中的顺序引用,新增模块都会导致序号的变化。有了NamedModulesPlugin,模块都拥有了姓名,而且都是独一无二的key,不管新增减少多少模块,模块的key都是固定的。
除了NamedmodulesPlugin,还有一个NamedChunksPlugin,这个是给配置的每个chunks命名,原本的chunks也是数组,没有名字。NamedChunksPlugin其实就是提供了一个功能,你可以自定义chunks的名字,假如我在不同的包中有相同的chunk名,怎么办?这个时候就要在进行进一步的区分了,我们可以用所有的依赖模块名加上本模块名,因为Chunk.modules已经废弃了,现在用其他的方法来代替chunk.mapModules,然后重命名chunk的名字
new webpack.NameChunksPlugin( (chunk) => {
return chunk.mapMudoles( m => {
return path.relative(m.context,m.request);
}).join('_')
})
总结:development也就给我们省略了命名的过程,但是其他还是要我们自己加的。
3、production
在正式版本中,所省略的插件们,如下所示,我们会一个个分析
//webpack.config.js
module.exports = {
mode:'production',
plugins: [
new UglifyJsPlugin(/*...*/),
new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") }),
new webpack.optimize.ModuleConcatenationPlugin(),
new webpack.NoEmitOnErrorsPlugin()
]
}
(1)UglifyJsPlugin
我们第一个需要处理的就是混淆&压缩js了吧,这个时候就要请出UglifyJs了,他在webpack中的名字是:const UglifyJsPlugin = require('uglifyjs-webpack-plugin');这样,就可以使用他了。不过 new UglifyJsPlugin() 这个插件我们可以在 optimize 中配置,效果是一样的,那么我们是不是不用在导入一个新的插件了,这样反而会拖慢webpack的打包速度
optimization: {
minimize: true
}
将插件去除,混淆压缩放入optimization,这样webpack速度快的起飞了,只有第一次打包会慢,之后在打包就快了
(2)ModuleConcatenationPlugin
webpack.optimize.ModuleConcatenationPlugin() 这个插件的作用是什么呢?此插件仅适用于由webpack直接处理的ES6模块,在使用转译器(transpiler)时,你需要禁用对模块的处理(例如Babel中的modules选项)。
(3)NoEmitOnErrorsPlugin
最后一个插件就是webpack.NoEmitOnErrorsPlugin(),这个就是用于防止程序报错,就算有错误也给我继续编译,很暴力的做法。
四、摇树优化
1、概念
- 代码不会被执行,不可到达
- 代码执行的结果不会被用到
- 代码只会影响死变量(只写不读)
if (false) {
console.log('这段代码永远不会执行')
}
摇树是一种消除死代码的方法,应用程序的依赖项是树状结构,树的每个节点都代表了一个依赖项,这些依赖项为应用程序提供了不同的功能,通过消除不需要的依赖项来减少树的节点,这个过程叫摇树。只能适用于es6模块的导入,不适用于commonJS的require,因为es6的模块是静态引入。
(1)应用程序采用按需加载的方式导出,没有被引用的模块不会被打包进来,减少包大小,缩小应用的加载时间。
(2)es6的模块是静态分析
(3)webpack自带tree shaking,只需要加些配置
// webpack.config.js
optimization: {
// 使用tree-shaking
usedExports: true, // mode为production时,默认开启
},
2、示例
// print.js:导出了两个函数
export const add = (a, b) => {
console.log(a + b);
}
export const minus = (a, b) => {
console.log(a - b);
}
// index.js:只引用了其中一个函数
import { add } from "./print";
add(1, 2);
tree-shaking结果:
mode:development,依然将未引入的函数打包了,只是有一句注释标记未被引用,这样做是为了在开发模式下调试方便,如果把代码删除,程序报错时,位置定位不准。
mode:production,打包后的代码被压缩,且未被引入的函数没有打包。
参考文章:https://blog.csdn.net/qq_40677590/article/details/106817327