在项目中我通过方法一定位到几处体积占用较大的库,其中一个便是 moment.js 这个日期处理库。对于一个日期处理的功能,为何这个库会占用如此大的体积,仔细查看发现当引用这个库的时候,所有的 locale 文件都被引入,而这些文件甚至在整个库的体积中占了大部分,因此当webpack打包时移除这部分内容会让打包文件的体积有所减小。
webpack自带的两个库可以实现这个功能:
IgnorePlugin
ContextReplacementPlugin
IgnorePlugin 的使用方法如下:
// 插件配置 plugins: [ // 忽略moment.js中所有的locale文件 new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), ], // 使用方式 const moment = require('moment'); // 引入zh-cn locale文件 require('moment/locale/zh-cn'); moment.locale('zh-cn');
ContextReplacementPlugin 的使用方法如下:
// 插件配置 plugins: [ // 只加载locale zh-cn文件 new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /zh-cn/), ], // 使用方式 const moment = require('moment'); moment.locale('zh-cn');
通过以上两种方式, moment.js 的体积大致能缩减为原来的四分之一。
模块化引入
在项目中我使用了 lodash 这个很常用的工具库,然而在代码定位的时候发现这个库也占了不少的体积。仔细想想,我们在使用这类工具库的时候往往只使用到了其中的很少的一部分功能,但却把整个库都引入了。因此这里也可以进一步优化,只引用需要的部分。
import {chain, cloneDeep} from 'lodash'; // 可以改写为 import chain from 'lodash/chain'; import cloneDeep from 'lodash/cloneDeep';
这样就可以只打包我们需要的部分功能。
通过CDN引用
对于一些必要的库,但又无法对该库进行更好的体积优化的话,可以尝试通过外部引入的方式来减小打包文件的体积。采用该方法只需要在cdn站点找到需要引用的库的外部链接,以及对webpack进行简单配置即可。
// 在html中添加script引用 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
// 这里externals的key指的是使用时需要require的包名,value指的是该库通过script引入后在全局注册的变量名 externals: { jquery: 'jQuery' } // 使用方法 require('jquery')
通过 DLLPlugin 和 DLLReferencePlugin 拆分文件
如果项目过大,打包的时间会相当的长,如果频繁更新上线则会不断对代码进行编译打包,浪费很多时间。这时我们便可以将那些不常更新的框架和库(如vue.js等)进行单独的编译打包,这样每次开发上线就只需要对我们的开发文件进行编译打包,这样可以极大地省去不必要的打包时间。而这种方法需要 DLLPlugin 和 DLLReferencePlugin 两个插件的配合来完成。
DLLPlugin
在使用这个插件时,我们需要单独创建一个配置文件,这里命名为 webpack.dll.config.js ,配置如下:
module.exports = { entry: { lib: ['vue', 'vuex', 'vue-resource', 'vue-router'] }, output: { path: path.resolve(__dirname, '../dist', 'dll'), filename: '[name].js', publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath, library: '[name]_library' }, plugins: [ new webpack.DefinePlugin({ 'process.env': '"production"' }), /** * path: manifest.json输出文件路径 * name: dll对象名,跟output.library保持一致 */ new webpack.DllPlugin({ context: __dirname, path: path.resolve(__dirname, '../dist/dll', 'lib.manifest.json'), name: '[name]_library' }) ] }
这里要注意几点:
entry 中写明所有要单独打包的模块
output 的 library 属性可以将dll包暴露出来
DLLPlugin 的配置中, path 指明 manifest.json 文件的生成路径, name 暴露出dll的函数名
运行该配置文件便可生成打包文件和 manifest.json 文件。
DLLReferencePlugin
对于该插件的配置,不需要像上面一样单独写配置文件,只需要在生产配置文件中添加如下代码:
new webpack.DllReferencePlugin({ context: __dirname, // 同dll配置的路径保持一致 manifest: require('../dist/dll/lib.manifest.json') // manifest的位置 }),
然后运行webpack,发现打包的速度得到了极大地提升,也不用每次更新代码的时候重复编译打包这些依赖库了。
其他
对于webpack的打包优化我大致就总结了上面的一些方法,而为了让页面更快的加载,有更好的用户体验,我们并不只是从打包上优化,也可以有其他方面的优化,这里我也简单提一下我使用过的方法。
开启Gzip压缩