-
Notifications
You must be signed in to change notification settings - Fork 30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
webpack打包分析与性能优化 #3
Comments
mark |
3 similar comments
mark |
mark |
mark |
mark |
写得好! |
刚刚使用了你的方法速度提升很快 。 请问一下 在使用happypack 的时候增加缓存配置 ,打包出来缓存文件会存放在 .webpack_cache/ 下面, 但是第二次打包的时候 ,没有反应 ,要把.webpack_cache / 删除才能打包 |
mark下 |
mark |
mark |
1 similar comment
mark |
m |
被 |
@imwtr 需要在 uglifyJS/uglifyES 中传入配置项才能生效哦,另外cache的配置我没搞清楚,ng项目里开启AOT慢的要死,求解 |
我是直接用这个配置的,发现它并没有压缩,把 new ParallelUglifyPlugin({
cacheDir: '.cache/',
uglifyJS:{
output: {
comments: false
},
compress: {
warnings: false
}
}
}) |
mark |
webpack-dev-server 与 webpack-dev-middleware 在性能上有取舍吗? |
mark |
想问下如果已经升级到了webpack4,splitChunks是不是可以直接替代DLL & DllReference了? |
mark |
1 similar comment
mark |
@imwtr 确实没压缩 |
mark |
1 similar comment
mark |
mark |
1 similar comment
mark |
eyes |
webpack打包分析与性能优化
背景
在去年年末参与的一个项目中,项目技术栈使用
react+es6+ant-design+webpack+babel
,生产环境全量构建将近三分钟,项目业务模块多达数百个,项目依赖数千个,并且该项目协同前后端开发人员较多,提高webpack 构建效率,成为了改善团队开发效率的关键之一。下面我将在项目中遇到的问题和技术方案沉淀出来与大家做个分享
从项目自身出发
我们的项目是将js分离,不同页面加载不同的js。然而分析webpack打包过程并针对性提出优化方案是一个比较繁琐的过程。首先我们需要知道webpack 打包的流程,从而找出时间消耗比较长的步骤,进而逐步进行优化。
在优化前,我们需要找出性能瓶颈在哪,代码组织是否合理,优化相关配置,从而提升webpack构建速度。
1.使用yarn而不是npm
由于项目使用npm安装包,容易导致在多关联依赖关系中,很可能某个库在指定依赖时没有指定版本号,进而导致不同设备上拉到的package版本不一。yarn不管安装顺序如何,相同的依赖关系将以相同的方式安装在任何机器上。当关联依赖中包括对某个软件包的重复引用,在实际安装时将尽量避免重复的创建。yarn不仅可以缓存它安装过的包,而且安装速度快,使用yarn无疑可以很大程度改善工作流和工作效率
2.删除没有使用的依赖
很多时候,我们由于项目人员变动比较大,参与项目的人也比较多,在分析项目时,我发现了一些问题,诸如:有些文件引入进来的库没有被使用到也没有及时删除,例如:
在业务中并没有使用到
a
模块,但webpack 会针对该import
进行打包一遍,这无疑造成了性能的浪费。webpack打包分析
1.打包过程分析
我们知道,webpack 在打包过程中会针对不同的资源类型使用不同的loader处理,然后将所有静态资源整合到一个bundle里,以实现所有静态资源的加载。webpack最初的主要目的是在浏览器端复用符合CommonJS规范的代码模块,而CommonJS模块每次修改都需要重新构建(rebuild)后才能在浏览器端使用。
那么, webpack是如何进行资源的打包的呢?总结如下:
我们的项目使用的就是多入口文件。在入口文件中,webpack会对每个资源文件进行配置一个id,即使多次加载,它的id也是一样的,因此只会打包一次。
实例如下:
main.js引用了chunk1、chunk2,chunk1又引用了chunk2,打包后:bundle.js:
2.如何定位webpack打包速度慢的原因
我们首先需要定位webpack打包速度慢的原因,才能因地制宜采取合适的方案。我们可以在终端中输入:
然后将输出的json文件到如下两个网站进行分析
这两个站点可以以可视方式呈现构造的组件,可以让你清楚的看到模块的组成部分,以及在项目中可能存在的多版本引用的问题,对于分析项目依赖有很大的帮助
优化方案与思路
针对webpack构建大规模应用的优化往往比较复杂,我们需要抽丝剥茧,从性能提升点着手,可能没有一套通用的方案,但大体上的思路是通用的,核心思路可能包括但不限于如下:
1):拆包,限制构建范围,减少资源搜索时间,无关资源不要参与构建
2):使用增量构建而不是全量构建
3):从webpack存在的不足出发,优化不足,提升效率
webpack打包优化
1.减小打包文件体积
webpack+react的项目打包出来的文件经常动则几百kb甚至上兆,究其原因有:
针对第一种情况,我们可以使用
extract-text-webpack-plugin
,但缺点是会产生更长时间的编译,也没有HMR,还会增加额外的HTTP请求。对于css文件不是很大的情况最好还是不要使用该插件。针对第二种情况,我们可以通过提取公共代码块,这也是比较普遍的做法:
通过这种方法,我们可以有效减少不同入口文件之间重叠的代码,对于非单页应用来说非常重要。
针对第三种情况,我们可以把React、ReactDOM缓存起来:
我们在开发环境使用react的开发版本,这里包含很多注释,警告等等。部署上线的时候可以通过
webpack.DefinePlugin
来切换生产版本。当然,我们还可以将React 直接放到CDN上,以此来减少体积。
2.代码压缩
webpack提供的UglifyJS插件由于采用单线程压缩,速度很慢 ,
webpack-parallel-uglify-plugin
插件可以并行运行UglifyJS插件,这可以有效减少构建时间,当然,该插件应用于生产环境而非开发环境,配置如下:3.happypack
happypack 的原理是让loader可以多进程去处理文件,原理如图示:
此外,happypack同时还利用缓存来使得rebuild 更快
4.缓存与增量构建
由于项目中主要使用的是react.js和es6,结合webpack的babel-loader加载器进行编译,每次重新构建都需要重新编译一次,我们可以针对这个进行增量构建,而不需要每次都全量构建。
babel-loader
可以缓存处理过的模块,对于没有修改过的文件不会再重新编译,cacheDirectory
有着2倍以上的速度提升,这对于rebuild 有着非常大的性能提升。babel-loader
让除了node_modules
目录下的js文件都支持es6语法,注意exclude: /node_modules/
很重要,否则 babel 可能会把node_modules
中所有模块都用 babel 编译一遍!当然,你还需要一个像这样的
.babelrc
文件,配置如下:这是一劳永逸的做法,何乐而不为呢?除此之外,我们还可以使用webpack自带的cache,以缓存生成的模块和chunks以提高多个增量构建的性能。
在webpack的整个构建过程中,有多个地方提供了缓存的机会,如果我们打开了这些缓存,会大大加速我们的构建
而针对增量构建 ,我们一般使用:
webpack-dev-server或webpack-dev-middleware,这里我们使用
webpack-dev-middleware
:通过设置
chunks:false
,可以将控制台输出的代码块信息关闭5.减少构建搜索或编译路径
为了加快webpack打包时对资源的搜索速度,有很多的做法:
大多数路径应该使用
resolve.root
,只对嵌套的路径使用Resolove.moduledirectories
,这可以获得显著的性能提升原因是
Resolove.moduledirectories
是取相对路径,所以比起resolve.root
会多parse很多路径:针对第三方NPM包,这些包我们并不会修改它,但仍然每次都要在build的过程消耗构建性能,我们可以通过DllPlugin来前置这些包的构建,具体实例:https://github.com/webpack/webpack/tree/master/examples/dll
我们使用dllplugin把第三方的NPM包生成一个名为
manifest.json
的文件,这个文件是用来让DLLReferencePlugin
映射到相关的依赖上去的。在文件中引入该dll文件即可。其原理是通过引用 dll 的 manifest 文件来把依赖的名称映射到模块的 id 上,之后再在需要的时候通过内置的__webpack_require__
函数来 require 他们resolve.alias
是webpack 的一个配置项,它的作用是把用户的一个请求重定向到另一个路径。 比如:这样我们在要打包的脚本中的使用
require('comps/Loading.jsx');
其实就等价于require('src/pages/components/Loading.jsx')
。webpack 默认会去寻找所有 resolve.root 下的模块,但是有些目录我们是可以明确告知 webpack 不要管这里,从而减轻 webpack 的工作量。这时会用到
module.noParse
参数在项目中合理使用 alias 和 noParse 可以有效提升效率,虽然不是很明显
以上配置均由本人给出,仅供参考(有些插件的官方文档给的不是那么明晰)
6.其他
babel-plugin-import
插件来按需加载模块结尾
虽然上面的做法减少了文件体积,加快了编译速度,整体构建(initial build)从最初的三分多钟到一分钟,rebuild十多秒,优化效果明显。但对于Webpack + React项目来说,性能优化方面远不止于此,还有很多的优化空间,比如服务端渲染,首屏优化,异步加载模块,按需加载,代码分割等等
The text was updated successfully, but these errors were encountered: