Vue项目Webpack优化实践,构建效率提高50%

本文分享了将Webpack构建速度提升50%的优化方法,包括缩小文件搜索范围、减少冗余代码、多进程处理文件、自动刷新、模块热替换、提取公共代码、按需加载、优化SourceMap及构建结果分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

是对Webpack构建进行优化变得刻不容缓。经过不断的摸索和实践,通过以下方法优化后,项目的构建速度提高了50%。现将相关优化方法进行总结分享。

1、缩小文件的搜索范围

1.1、优化Loader配置

   由于Loader对文件的转换操作很耗时,所以需要让尽可能少的文件被Loader处理。我们可以通过以下3方面优化Loader配置:(1)优化正则匹配(2)通过cacheDirectory选项开启缓存(3)通过include、exclude来减少被处理的文件。实践如下:

项目原配置:

 
  1. {

  2. test: /\.js$/,

  3. loader: 'babel-loader',

  4. include: [resolve('src'), resolve('test')]

  5. },复制代码

优化后配置:

 
  1. {

  2. // 1、如果项目源码中只有js文件,就不要写成/\.jsx?$/,以提升正则表达式的性能

  3. test: /\.js$/,

  4. // 2、babel-loader支持缓存转换出的结果,通过cacheDirectory选项开启

  5. loader: 'babel-loader?cacheDirectory',

  6. // 3、只对项目根目录下的src 目录中的文件采用 babel-loader

  7. include: [resolve('src')]

  8. },

  9. 复制代码

1.2、优化resolve.modules配置

   resolve.modules 用于配置Webpack去哪些目录下寻找第三方模块。resolve.modules的默认值是[node modules],含义是先去当前目录的/node modules目录下去找我们想找的模块,如果没找到,就去上一级目录../node modules中找,再没有就去../ .. /node modules中找,以此类推,这和Node.js的模块寻找机制很相似。当安装的第三方模块都放在项目根目录的./node modules目录下时,就没有必要按照默认的方式去一层层地寻找,可以指明存放第三方模块的绝对路径,以减少寻找。

优化后配置:

 
  1. resolve: {

  2. // 使用绝对路径指明第三方模块存放的位置,以减少搜索步骤

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

  4. },

  5. 复制代码

1.3、优化resolve.alias配置

   resolve.alias配置项通过别名来将原导入路径映射成一个新的导入路径。

如项目中的配置使用:

 
  1. alias: {

  2. '@': resolve('src'),

  3. },

  4. // 通过以上的配置,引用src底下的common.js文件,就可以直接这么写

  5. import common from '@/common.js';

  6. 复制代码

1.4、优化resolve.extensions配置

 
  1. 在导入语句没带文件后缀时,Webpack 会在自动带上后缀后去尝试询问文件是否存在。默认是:extensions :[‘. js ‘,’. json ’] 。也就是说,当遇到require ( '. /data ’)这样的导入语句时,Webpack会先去寻找./data .js 文件,如果该文件不存在,就去寻找./data.json 文件,如果还是找不到就报错。如果这个列表越长,或者正确的后缀越往后,就会造成尝试的次数越多,所以 resolve .extensions 的配置也会影响到构建的性能。

  2.  

优化措施:

<u> • 后缀尝试列表要尽可能小,不要将项目中不可能存在的情况写到后缀尝试列表中。</u>

<u> • 频率出现最高的文件后缀要优先放在最前面,以做到尽快退出寻找过程。</u>

<u> • 在源码中写导入语句时,要尽可能带上后缀,从而可以避免寻找过程。例如在确定的情况下将 require(’. /data ’)写成require(’. /data.json ’),可以结合enforceExtension 和 enforceModuleExtension开启使用来强制开发者遵守这条优化</u>

1.5、优化resolve.noParse配置

   noParse配置项可以让Webpack忽略对部分没采用模块化的文件的递归解析和处理,这 样做的好处是能提高构建性能。原因是一些库如jQuery、ChartJS 庞大又没有采用模块化标准,让Webpack去解析这些文件既耗时又没有意义。 noParse是可选的配置项,类型需要是RegExp 、[RegExp]、function中的一种。例如,若想要忽略jQuery 、ChartJS ,**则优化配置如下:**
 
  1. // 使用正则表达式

  2. noParse: /jquerylchartjs/

  3. // 使用函数,从 Webpack3.0.0开始支持

  4. noParse: (content)=> {

  5. // 返回true或false

  6. return /jquery|chartjs/.test(content);

  7. }

  8. 复制代码

2、减少冗余代码

    babel-plugin-transform-runtime 是Babel官方提供的一个插件,作用是减少冗余的代码 。 Babel在将ES6代码转换成ES5代码时,通常需要一些由ES5编写的辅助函数来完成新语法的实现,例如在转换 class extent 语法时会在转换后的 ES5 代码里注入 extent 辅助函数用于实现继承。babel-plugin-transform-runtime会将相关辅助函数进行替换成导入语句,从而减小babel编译出来的代码的文件大小。

3、使用HappyPack多进程解析和处理文件

   由于有大量文件需要解析和处理,所以构建是文件读写和计算密集型的操作,特别是当文件数量变多后,Webpack构建慢的问题会显得更为严重。运行在 Node.之上的Webpack是单线程模型的,也就是说Webpack需要一个一个地处理任务,不能同时处理多个任务。Happy Pack ( https://github.com/amireh/happypack )就能让Webpack做到这一点,它将任务分解给多个子进程去并发执行,子进程处理完后再将结果发送给主进程。

项目中HappyPack使用配置:

 
  1. (1)HappyPack插件安装:

  2. $ npm i -D happypack

  3. (2)webpack.base.conf.js 文件对module.rules进行配置

  4. module: {

  5. rules: [

  6. {

  7. test: /\.js$/,

  8. // 将对.js 文件的处理转交给 id 为 babel 的HappyPack实例

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

  10. include: [resolve('src'), resolve('test'),

  11. resolve('node_modules/webpack-dev-server/client')],

  12. // 排除第三方插件

  13. exclude:path.resolve(__dirname,'node_modules'),

  14. },

  15. {

  16. test: /\.vue$/,

  17. use: ['happypack/loader?id=vue'],

  18. },

  19. ]

  20. },

  21. (3)webpack.prod.conf.js 文件进行配置 const HappyPack = require('happypack');

  22. // 构造出共享进程池,在进程池中包含5个子进程

  23. const HappyPackThreadPool = HappyPack.ThreadPool({size:5});

  24. plugins: [

  25. new HappyPack({

  26. // 用唯一的标识符id,来代表当前的HappyPack是用来处理一类特定的文件

  27. id:'vue',

  28. loaders:[

  29. {

  30. loader:'vue-loader',

  31. options: vueLoaderConfig

  32. }

  33. ],

  34. threadPool: HappyPackThreadPool,

  35. }),

  36.  
  37. new HappyPack({

  38. // 用唯一的标识符id,来代表当前的HappyPack是用来处理一类特定的文件

  39. id:'babel',

  40. // 如何处理.js文件,用法和Loader配置中一样

  41. loaders:['babel-loader?cacheDirectory'],

  42. threadPool: HappyPackThreadPool,

  43. }),

  44. ]

  45. 复制代码

4、使用ParallelUglifyPlugin多进程压缩代码文件

   由于压缩JavaScript 代码时,需要先将代码解析成用 Object 抽象表示的 AST 语法树,再去应用各种规则分析和处理AST ,所以导致这个过程的计算量巨大,耗时非常多。当Webpack有多个JavaScript 文件需要输出和压缩时,原本会使用UglifyJS去一个一个压缩再输出,但是ParallelUglifyPlugin会开启多个子进程,将对多个文件的压缩工作分配给多个子进程去完成,每个子进程其实还是通过UglifyJS去压缩代码,但是变成了并行执行。所以 ParallelUglify Plugin能更快地完成对多个文件的压缩工作。

** 项目中ParallelUglifyPlugin使用配置:**

 
  1. (1)ParallelUglifyPlugin插件安装:

  2. $ npm i -D webpack-parallel-uglify-plugin

  3. (2)webpack.prod.conf.js 文件进行配置

  4. const ParallelUglifyPlugin =require('webpack-parallel-uglify-plugin');

  5. plugins: [

  6. new ParallelUglifyPlugin({

  7. cacheDir: '.cache/',

  8. uglifyJs:{

  9. compress: {

  10. warnings: false

  11. },

  12. sourceMap: true

  13. }

  14. }),

  15. ]

  16. 复制代码

5、使用自动刷新

   借助自动化的手段,在监听到本地源码文件发生变化时,自动重新构建出可运行的代码后再控制浏览器刷新。Webpack将这些功能都内置了,并且提供了多种方案供我们选择。

** 项目中自动刷新的配置:**

 
  1. devServer: {

  2. watchOptions: {

  3. // 不监听的文件或文件夹,支持正则匹配

  4. ignored: /node_modules/,

  5. // 监听到变化后等300ms再去执行动作

  6. aggregateTimeout: 300,

  7. // 默认每秒询问1000次

  8. poll: 1000

  9. }

  10. },

  11. 复制代码

**相关优化措施: **

<u>(1)配置忽略一些不监听的一些文件,如:node_modules。 </u>

<u>(2)watchOptions.aggregateTirneout 的值越大性能越好,因为这能降低重新构建的频率。</u>

<u>(3) watchOptions.poll 的值越小越好,因为这能降低检查的频率</u>。

6、开启模块热替换

DevServer 还支持一种叫做模块热替换( Hot Module Replacement )的技术可在不刷新整个网页的情况下做到超灵敏实时预览。原理是在一个源码发生变化时,只需重新编译发生变化的模块,再用新输出的模块替换掉浏览器中对应的老模块 。模块热替换技术在很大程度上提升了开发效率和体验 。

项目中模块热替换的配置:

 
  1. devServer: {

  2. hot: true,

  3. },

  4. plugins: [

  5. new webpack.HotModuleReplacementPlugin(),

  6. // 显示被替换模块的名称

  7. new webpack.NamedModulesPlugin(), // HMR shows correct file names

  8. ]

  9. 复制代码

7、提取公共代码

    如果每个页面的代码都将这些公共的部分包含进去,则会造成以下问题 : 

<u> • 相同的资源被重复加载,浪费用户的流量和服务器的成本。</u>

<u> • 每个页面需要加载的资源太大,导致网页首屏加载缓慢,影响用户体验</u>。

   如果将多个页面的公共代码抽离成单独的文件,就能优化以上问题 。Webpack内置了专门用于提取多个Chunk中的公共部分的插件CommonsChunkPlugin。 

项目中CommonsChunkPlugin的配置:

 
  1. // 所有在 package.json 里面依赖的包,都会被打包进 vendor.js 这个文件中。

  2. new webpack.optimize.CommonsChunkPlugin({

  3. name: 'vendor',

  4. minChunks: function(module, count) {

  5. return (

  6. module.resource &&

  7. /\.js$/.test(module.resource) &&

  8. module.resource.indexOf(

  9. path.join(__dirname, '../node_modules')

  10. ) === 0

  11. );

  12. }

  13. }),

  14. // 抽取出代码模块的映射关系

  15. new webpack.optimize.CommonsChunkPlugin({

  16. name: 'manifest',

  17. chunks: ['vendor']

  18. }),

  19. 复制代码

8、按需加载代码

   通过vue写的单页应用时,可能会有很多的路由引入。当打包构建的时候,javascript包会变得非常大,影响加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应的组件,这样就更加高效了。这样会大大提高首屏显示的速度,但是可能其他的页面的速度就会降下来。 

项目中路由按需加载(懒加载)的配置:

 
  1. const Foo = () => import('./Foo.vue')

  2. const router = new VueRouter({

  3. routes: [

  4. { path: '/foo', component: Foo }

  5. ]

  6. })复制代码

9、优化SourceMap

   我们在项目进行打包后,会将开发中的多个文件代码打包到一个文件中,并且经过压缩,去掉多余的空格,且babel编译化后,最终会用于线上环境,那么这样处理后的代码和源代码会有很大的差别,当有bug的时候,我们只能定位到压缩处理后的代码位置,无法定位到开发环境中的代码,对于开发不好调式,因此sourceMap出现了,它就是为了解决不好调式代码问题的。

** SourceMap的可选值如下:**

[图片上传失败...(image-97bc00-1545732488850)]

<u>开发环境推荐: cheap-module-eval-source-map </u>

<u>生产环境推荐: cheap-module-source-map </u>

**原因如下: **

1. 源代码中的列信息是没有任何作用,因此我们打包后的文件不希望包含列相关信息,只有行信息能建立打包前后的依赖关系。因此不管是开发环境或生产环境,我们都希望添加cheap的基本类型来忽略打包前后的列信息。

2. 不管是开发环境还是正式环境,我们都希望能定位到bug的源代码具体的位置,比如说某个vue文件报错了,我们希望能定位到具体的vue文件,因此我们也需要module配置。

3. 我们需要生成map文件的形式,因此我们需要增加source-map属性。

4. 我们介绍了eval打包代码的时候,知道eval打包后的速度非常快,因为它不生成map文件,但是可以对eval组合使用 eval-source-map使用会将map文件以DataURL的形式存在打包后的js文件中。在正式环境中不要使用 eval-source-map, 因为它会增加文件的大小,但是在开发环境中,可以试用下,因为他们打包的速度很快。

10、构建结果输出分析

   Webpack输出的代码可读性非常差而且文件非常大,让我们非常头疼。为了更简单、直观地分析输出结果,社区中出现了许多可视化分析工具。这些工具以图形的方式将结果更直观地展示出来,让我们快速了解问题所在。接下来讲解vue项目中用到的分析工具:webpack-bundle-analyzer 。

项目中在webpack.prod.conf.js进行配置:

 
  1. if (config.build.bundleAnalyzerReport) {

  2. var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

  3. webpackConfig.plugins.push(new BundleAnalyzerPlugin());

  4. }

  5. 执行 $ npm run build --report 后生成分析报告如下:复制代码

[图片上传失败...(image-e086ce-1545732488850)]


转载:https://juejin.im/post/5c1fa158f265da613c09cb36
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值