项目构建分析和 webpack 优化实践
加入新公司一个月,最近接手在做一个 chrom 浏览器插件的项目,开发过程中发现项目打包的时间很长,足足有30多秒,这是让人很难接受的,而且构建的显示了几条包体积过大的提示信息:
可以看到,打包后有三个包超过了建议的体积,是什么导致了打包时间长和包的体积过大呢?
下面通过一些具体方法来分析原因和解决这个问题。
什么原因导致构建包变得这么大?
为了分析是什么导致构建包为什么会变得这么大,可以安装 webpack-bundle-analyzer 插件,通过它可以直观地查看构建包中所有项目的大小。
npm install —save-dev webpack-bundle-analyzer
对应的需要在 webpack.config.js 中做如下配置:
const { BundleAnalyzerPlugin } = require(‘webpack-bundle-analyzer’) plugins: [
...,
new BundleAnalyzerPlugin({
analyzerPort: 8081,
}),
]
配置完成后再次运行构建 npm start,浏览器会自动打开 http://127.0.0.1:8081,在网页上可以看到构建包中每个文件的详细信息。
从图中可以找出影响体积的罪魁祸首有:
jquery、Moment、mammoth、html2canvas、xlsx、cpexcel、dexie 等
那么这些体积庞大的依赖库都需要打到项目的运行包里面吗?当然不是的。那我们逐步来优化这些依赖。
减少 moment 大小
moment 在包中占用了 545k 的体积,查看分析图可以看到,库文件中主要是各种用于支持语言版本的的locale文件,
但是项目中并不需要这部分功能,因此这部分数据是应该优化的。
查看项目中引入 moment 的方式
import moment form 'moment'
这样会将整个 moment 包都导入到文件中,为了避免导入不必要的文件,可以这么写:
import moment from 'moment/src/moment'
但是这么写会有个问题,如果项目中有新成员加入,极大的可能他不会这样写,而是像原来一样导入了整个 moment 包,因此为了避免这样的问题,可以考虑在 webpack 中创建一个别名,这样每次导入 moment 的时候就默认只导入文件夹下面的 moment.js 文件了,如下:
resolve: {
好了,重新启动服务进行打包,报错提示无法找到 ./locale:
查看 moment 的 官方 issue 发现这是一个存在已久的问题:moment.js 总是会加载 locales,还假定 locales 存在。你不能让 moment 只加载日期操作函数。
官方提供的解决方案是把 package.json 中的 Moment 的版本改成 2.18.1, 如下:
不过在 Stack Overflow 上找到了另一种解决方案:
简单介绍一下 IgnorePlugin
- 这是webpack内置插件
- 作用:忽略第三方包指定目录,让这些指定目录不要被打包进去
尝试一下,在 webpack.config.js 中添加如下配置:
plugins:[
// moment这个库中,如果引用了./locale/目录的内容,就忽略掉,不会打包进去
new Webpack.IgnorePlugin(/\.\/locale/,/moment/),
]
按照上面的方法,减小了 moment 的打包体积,同时也避免了报错,但是如果项目中需要用到语言包该怎么办呢?很简单,手动引入一下就可以了:
import moment from 'moment'
//手动引入所需要的语言包
import 'moment/locale/zh-cn';
moment.locale('zh-cn'); const r = moment().endOf('day').fromNow();
console.log(r);
Ok,这么一来能够显示中文,又把不必要的语言包都忽略打包了,重新构建一下,看一下体积有没有变化:
可以看到包已经缩减到了1.67M,打包时间缩短了29s(减少了4s),对应的观察网页上的显示结果,moment 包的大小也从 545k 变成了 155.32k,小了很多,不是吗?
使用 DllPlugin 加快打包速度
在用 Webpack 打包的时候,对于一些不经常更新的第三方库,比如 react,lodash,vue ,可以将这些库同项目代码分离开来,提前打包,从而每次只打包项目自身的代码,节省了打包时间。常用的方案是使用 DllPlugin。
如何使用 DllPlugin 呢?
首先在 webpack 文件夹下新建 webpack.dll.js文件
配置如下:
const webpack = require('webpack')
const path = require('path') module.exports = {
entry: {
// manifest 的前缀名,这里会在webpack 文件下生成一个dll.manifest.json 文件
dll: [
'react',
'react-dom',
'antd',
'classnames',
'jquery',
'xlsx',
'mammoth',
'html2canvas',
'dexie',
'cheerio', // 这些都是比较稳定,不常做修改的库文件
],
},
output: {
// 指定在 dist/static 下生成一个 dll.min.js 文件
path: path.join(__dirname, '../dist/static/'),
filename: '[name].min.js',
library: '[name]',
},
plugins: [
new webpack.DllPlugin({
// 指定在当前文件夹下生成 manifest 文件
path: path.resolve(__dirname, './dll.manifest.json'),
name: '[name]',
context: __dirname,
}),
// 压缩,让包更小一点
new webpack.optimize.UglifyJsPlugin({ minimize: true }),
],
}
配置完成后对应的需要在 webpack.config.js 中做如下修改:
const manifest = require('./dll.manifest.json')
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest,
})
]
然后在入口文件中引入 dll.min.js
对应的,为了方便启动,在 package.json 中添加快捷命令:
"scripts": {
"dll": "webpack —config webpack/webpack.dll.js",
}
到这里,DllPlugin 的相关配置就完成了,打包的时候执行 npm run dll 会在 webpack 目录下生成 dll.manifest.json 文件,在 dist/static 目录下会生成 dll.min.js 文件,在打包过程中, webpack 会将 webpack.dll.js 中配置包含的库做一个索引,并写在 dll.manifest.json 文件中,而引用 dll 的代码在打包的时候,只要读取这个 manifest 获取对应的库就可以了。
生成的 dll.manifest.json 文件
最后执行 npm run build 测试打包速度:
发现现在的打包时间不到19秒,相比于原来的33s减少了将近一半,对应两个比较大的包体积也各自减少了2/3 还多。所以使用了 DllPlugin 之后,对项目的打包效率的提升还是很明显的。
总结
项目最开始开始构建,打包后需要将近 4M 的空间,通过手动修改 moment 库的引入方式和引入 webpack 的 DllPlugin 进行优化,打包后最终体积减少到了 1.2M,压缩了一半多,对应打包时间也缩短了将近一半,所以通过 webpack 进行打包优化还是很有效果的。这给我的启发是,在实际开发和打包上线过程中,需要细致地评估项目的构建体积和打包时间,通过 webpack-bundle-analyzer 可以直观的观察构建包的构成和体积分布,并且根据分析的结果有针对性地进行优化,以此来精简项目体积,提升应用效率。当然,打包优化的方式不仅限于此,还可以通过 HappyPack 利用 Node 的多线程充分使用电脑多核来提升构建速度(但是实际效果不一定会变快),此外,还可以使用 webpack 的 externals 不打包某些文件,而在其他地方通过 cdn 引入,利用缓存下载 cnd 文件达到减少打包时间的目的,有兴趣可以在项目中尝试,相信你会有很多收获。
参考:
使用webpack的插件DllPlugin加快打包速度 - 前端下午茶
项目构建分析和 webpack 优化实践的更多相关文章
- Java SpringBoot 项目构建 Docker 镜像调优实践
PS:已经在生产实践中验证,解决在生产环境下,网速带宽小,每次推拉镜像影响线上服务问题,按本文方式构建镜像,除了第一次拉取.推送.构建镜像慢,第二.三-次都是几百K大小传输,速度非常快,构建.打包.推 ...
- Vue实战Vue-cli项目构建(Vue+webpack系列之一)
用Vue比较长一段时间了,大大小小做了一些项目,最近想总结一下知识点,出一个Vue+webpack系列,先从项目构建说起--vue-cli. 由于是Vue+webpack这里就不赘述git那些东西,默 ...
- React项目构建(利用webpack打包)
引言 最近React作为当前最为火热的前端框架.最近也相继而出来相关ES7的新语法. 当然,在使用React开发web项目的时候,不得不提到的就是与之配套的相应的打包技术,之前上文已经简单的提到Rea ...
- vue项目构建:vue-cli+webpack常用配置
1,Webpack-dev-server的proxy用法:https://www.jianshu.com/p/f489e7764cb8 2,vue-cli3搭建项目之webpack配置:https:/ ...
- 【Vuejs】335-(超全) Vue 项目性能优化实践指南
点击上方"前端自习课"关注,学习起来~ 前言 Vue 框架通过数据双向绑定和虚拟 DOM 技术,帮我们处理了前端开发中最脏最累的 DOM 操作部分, 我们不再需要去考虑如何操作 D ...
- 基于 Ant Desigin 的后台管理项目打包优化实践
背景 按照 Ant Design 官网用 React 脚手构建的后台项目,刚接手项目的时候大概30条路由左右,我的用的机子是 Mac 8G 内存,打包完成需要耗时2分钟左右,决定优化一下. 项目技术栈 ...
- webpack 教程 那些事儿04-webpack项目实战分析
这节主要讲解真正项目用用到的 webpack配置问题,项目实战篇 就像我们不会完全做一个项目,不用别人的轮子一样.这个配置我们借用 vue-cli 搭建的配置来研究,因为它已经足够优秀. 有了前面的基 ...
- paip.前端加载时间分析之道优化最佳实践
paip.前端加载时间分析之道优化最佳实践 1.另存为 ,查看文件尺寸..和图片. 2.view the 另存为的htm静态的文件单个的加载,看时间...可以排除编程语言的问题and 数据库.. ## ...
- 基于webpack+react+antd 项目构建
工欲善其事必先利其器,学习React也是如此. 下面分享一篇基于webpack+react+antd 项目构建的好文章, https://blog.hduzplus.xyz/articles/2017 ...
随机推荐
- centos7 添加用户,组
centos7添加用户,组. groupadd projectUsers //添加组,组名projectUser. cat /etc/group //查看最后一行是projectUser. 添加用户并 ...
- Centos7 安装jdk,MySQL
报名立减200元.暑假直降6888. 邀请链接:http://www.jnshu.com/login/1/20535344 邀请码:20535344 学习阿里云平台的云服务器配置Java开发环境.我现 ...
- CAD2014学习笔记-图纸布局和打印输出
基于 虎课网huke88.com CAD教程 图纸设计规范:施工图 封面设计:地点.名称.设计人 目录设计:施工图编号.名称.意义.对应页数.注释.图号序号:包括平面.立面.大样图.施工图 设计说明/ ...
- DataGrid通过DataSet保存为xml文件,并导入
做了个小的DataGrid通过DataSet保存为xml_测试,DataGrid通过DataSet保存为xml_测试,通过dataSet.writeXML()和dataSet.readXML()方法完 ...
- vue2.0 富文本组件(基于wangeditor)
1. 本组件基于 wangeditor http://www.wangeditor.com/ 如有侵权 请告知, 2. 效果图 3. 依赖安装 package.json 中 devDependenci ...
- 跟着大彬读源码 - Redis 6 - 对象和数据类型(下)
继续撸我们的对象和数据类型. 上节我们一起认识了字符串和列表,接下来还有哈希.集合和有序集合. 1 哈希对象 哈希对象的可选编码分别是:ziplist 和 hashtable. 1.1 ziplist ...
- python迭代器-迭代器取值-for循环-生成器-yield-生成器表达式-常用内置方法-面向过程编程-05
迭代器 迭代器 迭代: # 更新换代(其实也是重复)的过程,每一次的迭代都必须基于上一次的结果(上一次与这一次之间必须是有关系的) 迭代器: # 迭代取值的工具 为什么用迭代器: # 迭代器提供了一种 ...
- 针对Nginx日志中出现的漏洞扫描与爬虫的三种措施
0x001 使用fail2ban工具结合防火墙(iptables | firewalld),将大量404请求的IP地址封了.(详见fail2ban使用说明:https://www.cnblogs.co ...
- ThinkPHP 添加数据到数据库失败
ThinkPHP 添加数据到数据库失败 一般情况下会先检查一下几个方面 检查控制器或Model名是否有误 检查需要插入的数据是否为空或者缺失参数 检查数据表名及字段名称(大部分下都是字段名有误出错的) ...
- Spring + RocketMQ使用
本文所介绍环境为win7环境下运行, 从官方github中(https://github.com/alibaba/RocketMQ)下载RocketMQ-master.zip,版本为v3.5.8,解压 ...