webpack选择性编译
项目背景
项目中有些地方引用了本地的mock数据,这些数据全部在一个mock.js的文件中,由于数据较多,比较占位置,所以想在生产环境下移除该部分代码。具体实现还得靠webpack插件。以这个demo为例进行讲解。
关键点
- webpack.DefinePlugin 定义工程中的全局变量,本项目中定义了ISDEBUG来判断运行环境是否是生产环境
- terser-webpack-plugin 压缩代码,与uglifyjs-webpack-plugin功能一样,甚至参数都相差不大。但是对于ES6的支持程度比后者更好。该插件优化项之一是去除项目中无效代码,这是核心依赖项
- webpack-bundle-analyzer 分析打包结果
- 项目中mock.js的引用方式要使用Commonjs标准的require(‘mock’)
项目目录结构
1 | ├─config // webpack配置 |
项目中service下的每个文件都会引用mock.js文件。优化前,这些文件内容如下:
1 | // mock.js |
1 | // service下的js文件 |
1 | <!-->views下的页面文件<--> |
没有优化的打包结果:

优化步骤
webpack增加配置:terser-webpack-plugin
mock.js文件中的数据只是本地调试时使用的,所以,我们的目的是在生产环境下移除这部分代码。在上文我们提到的简化代码的插件terser-webpack-plugin,它使用terser.js来优化代码,并且有一项功能,就是打包时移除无效代码:

什么是无效代码,就像这种:
1 | if (false) { |
所以我们需要对mock文件引用方式做一个调整
更新本地文件引用方式
require与import的区别
在这里需要说一下require与import引入模块的一些区别。因为我们需要把项目中引用模块的方式由ES6的import全部改成Commonjs标准的require。原因如下:
- import是ES6的模块引入方式,它是在JS引擎编译阶段执行的。在代码运行前,遇到import就会生成一个只读引用,然后在运行阶段,碰到有用到引入模块值的再去引用模块取值,可能项目中并没有引用引入模块的值,但是已经声明了,就会执行。所以无法在生产环境下移除该部分代码,
- require是运行时执行,可以做到按需加载。
- 以后import可能也会支持按需引入,在ES2020提案中,可以使用import(‘module’)来按需加载。目前可以使用babel的@babel/plugin-syntax-dynamic-import插件进行兼容
优化结果
修改文件引用方式:
1 | // mock.js |
1 | // service下的js文件 |
1 | // webpack部分增加配置 |
优化结果如下,mock.js已经没有了

方案更新
- 使用webpack内置插件ProvidePlugin全局引入公共模块,需要使用时即可直接使用,无需每次手动require引入
尝试方案
在这之前,还试过webpack属性external,但无法达成目的。因为它的作用是打包时排除某一个已经采用CDN或其他方式引用的库或文件。关键点是已经设置了CDN等别的引入方式。因为打包之后该引用的地方还是会继续引用,区别是本地环境下,可能从本地node_modules引入。打包时,webpack会自动排除该文件,改从已经设置好的CDN引入了,这样可以极大的减少打包体积,但是会增加网络请求量,使用时也要权衡利弊。这个属性之前没怎么用过,不然也不会在这里采坑~
总结
- 使用webpack.DefinePlugin定义全局变量ISDEBUG控制代码是否有效;
- 使用require按需引入,或用ProvidePlugin全局引入;
- 使用terser-webpack-plugin优化代码,移除无效代码