专栏名称: SegmentFault思否
SegmentFault (www.sf.gg)开发者社区,是中国年轻开发者喜爱的极客社区,我们为开发者提供最纯粹的技术交流和分享平台。
目录
相关文章推荐
程序猿  ·  41岁DeepMind天才科学家去世:长期受 ... ·  昨天  
程序员小灰  ·  清华大学《DeepSeek学习手册》(全5册) ·  2 天前  
程序员的那些事  ·  成人玩偶 + ... ·  4 天前  
程序员小灰  ·  DeepSeek做AI代写,彻底爆了! ·  4 天前  
51好读  ›  专栏  ›  SegmentFault思否

Webpack 构建速度优化

SegmentFault思否  · 公众号  · 程序员  · 2019-03-18 08:00

正文

如何输出Webpack构建分析

输出Webpack构建信息的 . json 文件:

  1. webpack --profile --json > starts.json

说明:

  1. -- profile :记录构建中的耗时信息。

  2. -- json :以json格式输出构建结果,最后只输出一个json文件(包含所有的构建信息)。

web可视化查看构建分析

得到了webpack构建信息文件 starts . json ,如何进行很好的可视化查看?

1、可视化分析工具Webpack Analyse

Webpack Analyse是个在线Web应用,上传 starts . json 文件就可以。

2、webpack-bundle-analyzer

安装:

  1. npm i -g webpack-bundle-analyzer

生成 starts . json 后,直接在其文件夹目录执行

  1. webpack-bundle-analyzer

浏览器会打开对应网页并展示构建分析文档地址webpack-bundle-analyzer。

3、webpack-dashboard

webpack-dashboard是一款统计和优化webpack日志的工具,可以以表格形势展示日志信息。其中包括构建过程和状态、日志以及涉及的模块列表。

4、jarvis

jarvis是一款基于webapck-dashboard的webpack性能分析插件,性能分析的结果在浏览器显示,比webpack-bundler-anazlyer更美观清晰GitHub文档地址。

安装:

  1. npm i -D webpack-jarvis

webpack . config . js 配置:

  1. const Jarvis = require("webpack-jarvis");


  2. plugins: [

  3. new Jarvis({

  4. watchOnly: false,

  5. port: 3001 // optional: set a port

  6. })

  7. ];

参数说明:

  • port:监听的端口,默认1337,监听面板将监听这个端口,通常像http://localhost:port/。

  • host:域名,默认localhost,不限制域名。

  • watchOnly:仅仅监听编译阶段。默认为true,如果高为false,jarvis不仅仅运行在编译阶段,在编译完成后还保持运行状态。

  • 界面:看到构建时间为: Time : 11593ms (作为优化时间对比)。

webpack配置优化

webpack在启动时会从配置的Entry出发,解析出文件中的导入语句,再递归解析。

对于导入语句Webpack会做出以下操作:

  1. 根据导入语句寻找对应的要导入的文件;

  2. 在根据要导入的文件后缀,使用配置中的Loader去处理文件(如使用ES6需要使用babel-loader处理)。

针对这两点可以优化查找途径:

1、优化Loader配置

Loader处理文件的转换操作是很耗时的,所以需要让尽可能少的文件被Loader处理。

  1. {

  2. test: /\.js$/,

  3. use: [

  4. 'babel-loader?cacheDirectory',//开启转换结果缓存

  5. ],

  6. include: path.resolve(__dirname, 'src'),//只对src目录中文件采用babel-loader

  7. exclude: path.resolve(__dirname,' ./node_modules'),//排除node_modules目录下的文件

  8. },

2、优化resolve.modules配置

resolve . modules 用于配置webpack去哪些目录下寻找第三方模块,默认是 [ 'node_modules' ] ,但是,它会先去当前目录的 ./ node_modules 查找,没有的话再去 ../ node_modules 最后到根目录。

所以当安装的第三方模块都放在项目根目录时,就没有必要安默认的一层一层的查找,直接指明存放的绝对位置。

  1. resolve : {

  2. modules: [path.resolve(__dirname, 'node_modules')],

  3. }

3、优化resolve.extensions配置

在导入没带文件后缀的路径时,webpack会自动带上后缀去尝试询问文件是否存在,而 resolve . extensions 用于配置尝试后缀列表;默认为 extensions :[ 'js' , 'json' ]

当遇到 require ( './data' ) 时webpack会先尝试寻找 data . js ,没有再去找 data . json ;如果列表越长,或者正确的后缀越往后,尝试的次数就会越多。

所以在配置时为提升构建优化需遵守:

  1. 频率出现高的文件后缀优先放在前面。

  2. 列表尽可能的小。

  3. 书写导入语句时,尽量写上后缀名。

因为项目中用的 jsx 较多,所以配置 extensions : [ ".jsx" , ".js" ]

基本配置后查看构建速度: Time : 10654ms ,配置前为 Time : 11593ms

使用DllPlugin优化

在使用webpack进行打包时候,对于依赖的第三方库,如react、react-dom等这些不会修改的依赖,可以让它和业务代码分开打包。

只要不升级依赖库版本,之后webpack就只需要打包项目业务代码,遇到需要导入的模块在某个动态链接库中时,就直接去其中获取;而不用再去编译第三方库,这样第三方库就只需要打包一次。

接入需要完成的事

  1. 将依赖的第三方模块抽离,打包到一个个单独的动态链接库中。

  2. 当需要导入的模块存在动态链接库中时,让其直接从链接库中获取。

  3. 项目依赖的所有动态链接库都需要被加载。

接入工具(webpack已内置)

  1. DllPlugin插件:用于打包出一个个单独的动态链接库文件。

  2. DllReferencePlugin:用于在主要的配置文件中引入 DllPlugin 插件打包好的动态链接库文件。

配置webpack_dll.config.js,构建动态链接库

  1. const path = require('path');

  2. const DllPlugin = require('webpack/lib/DllPlugin');


  3. module.exports = {

  4. mode: 'production',

  5. entry: {

  6. // 将React相关模块放入一个动态链接库

  7. react: ['react','react-dom','react-router-dom','react-loadable'],

  8. librarys : ['wangeditor'],

  9. utils: ['axios','js-cookie']

  10. },

  11. output: {

  12. filename: '[name]-dll.js',

  13. path: path.resolve(__dirname, 'dll'),

  14. // 存放动态链接库的全局变量名,加上_dll_防止全局变量冲突

  15. library: '_dll_[name]'

  16. },

  17. // 动态链接库的全局变量名称,需要可output.library中保持一致,也是输出的manifest.json文件中name的字段值

  18. // 如react.manifest.json字段中存在"name":"_dll_react"

  19. plugins: [

  20. new DllPlugin({

  21. name: '_dll_[name]',

  22. path: path .join(__dirname, 'dll', '[name].manifest.json')

  23. })

  24. ]

  25. }

webpack.pro.config.js中使用

  1. const DllReferencePlugin = require('webpack/lib/DllReferencePlugin');

  2. ...

  3. plugins: [

  4. // 告诉webpack使用了哪些动态链接库

  5. new DllReferencePlugin({

  6. manifest: require('./dll/react.manifest.json')

  7. }),

  8. new DllReferencePlugin({

  9. manifest: require('./dll/librarys.manifest.json')

  10. }),

  11. new DllReferencePlugin({

  12. manifest: require('./dll/utils.manifest.json')

  13. }),

  14. ]

注意:在 webpack_dll . config . js 文件中, DllPlugin 中的name参数必须和 output . library 中的一致;因为 DllPlugin 的name参数影响输出的 manifest . json 的name;而 webpack . pro . config . js 中的 DllReferencePlugin 会读取 manifest . json 的name,将值作为从全局变量中获取动态链接库内容时的全局变量名。

执行构建

  1. webpack -- progress -- colors -- config ./ webpack . dll . config . js

  2. webpack -- progress -- colors -- config ./ webpack . prod . js

html中引入dll.js文件。

构建时间对比: [ "11593ms" , "10654ms" , "8334ms" ]

HappyPack并行构建优化

核心原理:将webpack中最耗时的loader文件转换操作任务,分解到多个进程中并行处理,从而减少构建时间。

接入HappyPack:

  1. 安装: npm i - D happypack

  2. 重新配置 rules 部分,将 loader 交给 happypack 来分配。

代码:

  1. const HappyPack = require('happypack' );

  2. const happyThreadPool = HappyPack.ThreadPool({size: 5}); //构建共享进程池,包含5个进程

  3. ...

  4. plugins: [

  5. // happypack并行处理

  6. new HappyPack({

  7. // 用唯一ID来代表当前HappyPack是用来处理一类特定文件的,与rules中的use对应

  8. id: 'babel',

  9. loaders: ['babel-loader?cacheDirectory'],//默认设置loader处理

  10. threadPool: happyThreadPool,//使用共享池处理

  11. }),

  12. new HappyPack({

  13. // 用唯一ID来代表当前HappyPack是用来处理一类特定文件的,与rules中的use对应

  14. id: 'css',

  15. loaders: [

  16. 'css-loader',

  17. 'postcss-loader',

  18. 'sass-loader'],

  19. threadPool: happyThreadPool

  20. })

  21. ],

  22. module: {

  23. rules: [

  24. {

  25. test: /\.(js|jsx)$/,

  26. use: ['happypack/loader?id=babel'],

  27. exclude: path.resolve(__dirname,' ./node_modules'),

  28. },

  29. {

  30. test: /\.(scss|css)$/,

  31. //使用的mini-css-extract-plugin提取css此处,如果放在上面会出错

  32. use: [







请到「今天看啥」查看全文