一次vue2项目打包构建优化过程

63 篇文章 0 订阅
9 篇文章 0 订阅

记一次vue2项目构建优化过程。

项目基本情况

项目是一个vue2+webpack4的管理平台,

接下来看一下项目的打包耗时情况和产物依赖情况

耗时情况

首先使用SpeedMeasurePlugin来看一下项目的构建过程中各个阶段的耗时情况。

 

ini

复制代码

const SpeedMeasurePlugin = require("speed-measure-webpack-plugin"); const smp = new SpeedMeasurePlugin(); ​ module.exports = {  configureWebpack: smp.wrap({    // 在这里配置原本的Webpack配置    // 可以定义entry、output、module等配置 }) };

使用SpeedMeasurePlugin分析打包情况,项目总体耗时43s,其中有一些loader耗时过长,会帮我们标红,尤其是vue-loadersass-loaderpostcss-loader耗时过长,后续可以考虑使用缓存,并行处理使用thread-loader来优化。

产出依赖

webpack-bundle-analyzer使用这个插件,可以帮助分析项目的构建结果,以识别过大的模块、重复的依赖和不必要的代码。一旦你生成了可视化分析界面,可以按照以下方式来进行分析:

  1. 查看模块大小

    • 通过可视化界面,可以看到每个模块的大小。这可以帮助识别哪些模块尺寸过大,从而考虑是否需要对其进行优化,例如拆分代码、按需加载等。
  2. 检查重复的依赖

    • 可以查看依赖关系图,识别是否有重复的依赖被打包进了多个bundle中。这可能意味着某些依赖被重复引入,可以考虑通过Webpack的代码拆分功能或其他优化策略来避免重复打包。
  3. 识别不必要的代码

    • 通过分析模块之间的依赖关系,可以发现是否有一些不必要的代码被打包进了bundle中。这可能是因为某些模块被错误引入,或者存在无用的代码。通过分析依赖关系,可以识别并清理这些不必要的代码。
  4. 查看模块间的依赖关系

    • 了解模块之间的依赖关系可以帮助你优化代码拆分策略,以减少不必要的依赖关系,提高构建性能。

首先安装插件npm install --save-dev webpack-bundle-analyzer

 

ini

复制代码

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; ​ module.exports = { configureWebpack: {    plugins: [      new BundleAnalyzerPlugin()   ] } }

浏览器打开了一个http://127.0.0.1:8888/的页面,页面上就是我们项目的产物依赖情况,

发现比较大的产物就是echarts、element-ui.common,js和wangeditor,这个后续可以考虑按需加载、使用CDN引入和压缩。

开始优化
升级webpack

为啥把webpack升级放到第一个,个人喜好吧,觉得这个升级可能是性能提升最大的一个。

首先下载一个npm-check,查看当前npm依赖包的情况,有些可能会出现npm证书的情况,比如我的旧项目,做法也比较简单,切换到最新的淘宝镜像源,然后删掉node_modules,重新安装即可。

运行npx npm-check就可以了,或者也可以全局安装。

npm-check是一个用于检查项目中npm依赖包是否有更新版本的工具。通过运行npm-check命令,可以列出当前项目中已安装的npm包,并显示它们是否有可用的更新版本。这样可以帮助开发者及时了解项目依赖包的更新情况,及时更新以确保项目的安全性和稳定性。

会出现这么几种情况,根据具体的保存信息自行调整。 😎 MAJOR UP 有一个或多个主要版本更新可用,建议及时更新以获取最新功能和修复bug。 😕 NOTUSED 表示该依赖包未被项目使用,可以考虑移除以减少项目的依赖项数量。

😟 PKG ERR!表示在检查依赖包时出现错误,可能是由于网络问题或依赖包本身存在问题导致的。 😟 MISSING!表示在项目中缺少某个依赖包,可能会影响项目的正常运行,需要及时安装该依赖包。

接下来使用npm-check-updates 来检查依赖库可更新的版本

运行npx npm-check-updates即可

npm-check-updates是一个npm包,它可以帮助你检查当前项目中的npm依赖包是否有可用的更新版本。通过运行npm-check-updates命令,你可以快速了解哪些依赖包可以更新到最新版本,以便及时更新你的项目依赖,保持项目的安全性和稳定性。这个工具可以帮助你轻松地管理npm依赖版本,提高项目的维护效率。npm check-updates包含以下常用命令:

  1. npm-check-updates:检查当前项目中哪些npm包可以更新到最新版本。
  2. npm-check-updates -u:将package.json文件中的依赖版本号更新为最新版本。
  3. npm-check-updates -a:显示所有可用的更新,包括主要版本更新。
  4. npm-check-updates -g:检查全局安装的npm包是否有可用更新。
  5. npm-check-updates -f <filter>:根据提供的过滤器筛选要检查的依赖包。
  6. npm-check-updates -x <exclude>:排除特定的依赖包不进行检查。

npm-check-updates -p <packageManager>:指定要使用的包管理器,如npm或yarn。

运行npx npm-check-updates -u在package.json中的依赖便被更新了

因为这里只关注webpack及相关依赖,不涉及vue,于是将vue-router,vuex,vue-template-compiler还原。

运行npm i再重新安装这些依赖即可。

安装完毕后,运行vue inspect > webpack-config.js重新查看配置情况

报错

Error: Cannot find module 'webpack/lib/RequestShortener'

于是手动更新webpack,npm install webpack@latest --save-dev

再运行vue inspect > webpack-config.js ERROR Error: Cannot call .tap() on a plugin that has not yet been defined. Call plugin('preload').use() first. Error: Cannot call .tap() on a plugin that has not yet been defined. Call plugin('preload').use() first.

这个错误通常是由于Webpack插件的使用顺序问题导致的。具体来说,Webpack要求在调用.tap()方法之前,必须先调用.use()方法来定义插件。

需要更改下插件的调用方式

比如原先的:

 

ruby

复制代码

config.plugin("preload").tap(() => [     {        rel: "preload",        // to ignore runtime.js        // https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/cli-service/lib/config/app.js#L171        fileBlacklist: [/.map$/, /hot-update.js$/, /runtime..*.js$/],        include: "initial",     },   ]);

改成:

 

javascript

复制代码

const PreloadWebpackPlugin = require('preload-webpack-plugin'); config.plugin('preload').use(PreloadWebpackPlugin, [     {        rel: 'preload',        fileBlacklist: [/.map$/, /hot-update.js$/, /runtime..*.js$/],        include: 'initial',     },   ]);

接着依次更改下所使用的插件

随后运行vue inspect > webpack-config.js

报错:

Error: Cannot find module 'preload-webpack-plugin'

查找了些资料发现:

在Webpack 5中,一些插件或工具可能需要额外安装,这可能是因为Webpack 5对插件系统或依赖项有所改变,导致某些插件不再默认包含在Webpack中。这可能是为了减少Webpack的体积,提高灵活性,或者是对插件生态系统的调整。

于是安装npm install preload-webpack-plugin

再次运行vue inspect > webpack-config.js

可以看到根目录下出现了一个webpack.config.js配置文件。

开始运行项目npm run serve

问题1:

发现报错 ERROR TypeError: compiler.plugin is not a function TypeError: compiler.plugin is not a function 发现 preload-webpack-plugin和webpack5不兼容,

暂时先干掉

问题2

发现报错 options has an unknown property 'overlay'. These properties are valid:webpack

在将webpack4升级到webpack5时,webpack-dev-server的配置项发生了一些变化。对于overlay属性,webpack5中已经不再支持这个属性,而是使用了新的方式来处理警告和错误。可以将overlay属性替换为client属性,并设置overlay为true来实现类似的功能。

原来的

 

yaml

复制代码

devServer: {    port: port,    open: true,    overlay: {      warnings: false,      errors: true,   },    ...

现在的

 

yaml

复制代码

devServer: {    port: port,    open: true,    client: {      overlay: {        warnings: false,        errors: true     }   },

问题3:

继续报错

[@vue/compiler-sfc] the >>> and /deep/ combinators have been deprecated. Use :deep() instead. >>>和/deep/这两个组合选择器已经被弃用,取而代之的是使用:deep()伪类选择器来实现相同的功能。 这个需要更改原先的业务代码,而且改动较大,暂时搁置

问题4:

代码有很多不规范的写法导致编译报错

VueCompilerError: <template v-for> key should be placed on the <template> tag

Vue编译器错误,提示你在使用<template v-for>时应该将key属性放在<template>标签上而不是放在内部元素上。

将不规范的地方改过来即可。

问题4:

项目启动之后,获取不到process.env.VUE_APP_BASE_API,经过各种搜索发现

因为Webpack在构建过程中会将.env文件中的变量注入到process.env中,但这些变量在Vue组件中不会直接可见。

为了在Vue组件中访问.env文件中的变量,可以使用webpack.DefinePlugin插件将这些变量注入到Vue应用的全局变量中。你可以在vue.config.js中进行如下配置

 

arduino

复制代码

chainWebpack: config => {    config.plugin('define').use(require('webpack').DefinePlugin, [     {        'process.env': {          VUE_APP_BASE_API: JSON.stringify(process.env.VUE_APP_BASE_API)       }     }   ]); }

问题5:

 

vbnet

复制代码

BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default. This is no longer the case. Verify if you need this module and configure a polyfill for it. ​ If you want to include a polyfill, you need to:        - add a fallback 'resolve.fallback: { "path": require.resolve("path-browserify") }'        - install 'path-browserify' If you don't want to include a polyfill, you can use an empty module like this:        resolve.fallback: { "path": false }

Webpack 5不再默认包含Node.js核心模块的polyfill,需要手动配置polyfill来解决这个问题。

手动安装npm install path-browserify --save

添加配置

 

css

复制代码

resolve: {      alias: {        ...     },      fallback: {        "path": require.resolve("path-browserify")     }   },

问题6:

 

bash

复制代码

ERROR in ./node_modules/vue-i18n/dist/vue-i18n.mjs 452:27-35 export 'computed' (imported as 'computed') was not found in 'vue' (possible exports: default) @ ./src/main.js 36:0-31

这个是版本不兼容导致的,在package.json中对vue-i18n进行还原,然后重新安装

至此我们的项目已经可以跑起来了。

运行打包命令,发现时间比我们没升级前要长,可能是

  1. 缺少缓存:Webpack 5 默认启用了持久化缓存(persistent caching),但是在升级过程中可能没有正确配置缓存导致重新构建所有模块,从而增加了打包时间。
  2. 模块解析速度变慢:Webpack 5 在模块解析方面进行了一些改进,但这也可能导致解析速度变慢。

当我们设置缓存和打包环境:

 

css

复制代码

configureWebpack: {    cache: {      type: 'filesystem',   },    mode: 'production', },

打包时间一下子缩减到20s,优化幅度很大了。后续再从其他方面进一步优化。

缓存

这里主要给babel添加loader缓存

 

css

复制代码

{  loader: 'cache-loader', // 使用缓存  options: {    cacheDirectory: path.resolve(__dirname, '.cache/babel-loader'), // 缓存目录 }, }, {  loader: 'babel-loader',  options: {    cacheDirectory: true, // 同样启用Babel自身的缓存    presets: ['@babel/preset-env'],    plugins: ['@babel/plugin-proposal-class-properties'], }, },

再添加个vue-loader缓存

 

arduino

复制代码

configureWebpack: config => {    config.module     .rule('vue')     .test(/.vue$/)     .use('cache-loader')     .before('vue-loader')     .loader('cache-loader')     .options({        cacheDirectory: path.resolve(__dirname, '.cache/vue-loader'), // 设置缓存目录     }); },

General output time took 14.6 secs,时间降低到14.6,很快了。

压缩

在webpack5中,当mode设置为production时,默认会压缩代码的,这里实际上不需要额外的设置。然而涉及到图片,还是需要处理下的

 

yaml

复制代码

{          test: /.(png|jpe?g|gif)$/i,          use: [           {              loader: 'url-loader',              options: {                limit: 8192, // 小于8KB的图片将被转换为base64编码             },           },           {              loader: 'image-webpack-loader',              options: {                mozjpeg: {                  progressive: true,                  quality: 65,               },                optipng: {                  enabled: false,               },                pngquant: {                  quality: [0.65, 0.9],                  speed: 4,               },                gifsicle: {                  interlaced: false,               },             },           },         ],       },       {          test: /.svg$/,          use: [           {              loader: 'url-loader',              options: {                limit: 8192, // 小于8KB的SVG将被转换为base64编码             },           },           {              loader: 'svgo-loader',              options: {                plugins: [                 { removeViewBox: false },                 { removeDimensions: true },               ],             },           },         ],       },

General output time took 13.47 secs

并行构建
 

arduino

复制代码

config.module     .rule('js')     .use('thread-loader')     .loader('thread-loader')     .options({        workers: 4 // 指定worker     })     .end();

理想的worker数量通常不应超过你的CPU核心数。如果你有一个4核CPU,通常设置2到4个worker是合理的。设置过多的worker可能会导致上下文切换开销,反而降低效率。最好的办法就是多尝试:比如我的电脑就是8核的,不定的设置workers数,8、6、4、2,发现4效果最好,那就是他了。

General output time took 13.15 secs

最后打包时间为13s左右,发现其实效果没有之前那么显著了,

代码分隔
 

php

复制代码

config.optimization.splitChunks({      chunks: 'all',      minSize: 30000,      minChunks: 1,      cacheGroups: {        vendor: {          test: /[\/]node_modules[\/]/,          name: 'vendors',          priority: -10,       },        default: {          minChunks: 2,          priority: -20,          reuseExistingChunk: true,       },     },   });

webpack会根据这些规则将公共的依赖模块提取到单独的文件中,避免重复加载。

General output time took 13.57 secs

打包优化时间也是没什么变化。

至于cdn引入,按需加载第三方那个库,这就涉及到业务代码的改动,投入产出不成正比,就不动它了。还有在.gitignore文件中添加*.cache,因为新建了缓存目录,导致会多出很多文件,这个没必要添加到git上去的。

至此构建优化就到此为止了,打包时间从43s优化至13.57s,算是很大的优化了,热更新的时间也是1s左右的。

也想过换成vite试试,查过资料后换vite更是麻烦,一般的流程就是新建一个vite项目,然后将业务代码迁移过去,怕出错,就不试了。


原文链接:https://juejin.cn/post/7373659736300584987
 

  • 17
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于Vue项目打包速度优化,可以尝试以下几种方法: 1. 使用CDN:将一些常用的第三方库(如VueVuex、Vue Router等)从本地打包中移除,改为通过CDN引入。这样可以减少打包体积和加快打包速度。 2. 按需引入组件:在使用UI组件库时,可以考虑按需引入组件,而不是全部引入。这可以通过babel-plugin-component等工具来实现,减少不必要的打包和编译时间。 3. 代码拆分:将大型的代码块拆分成更小的模块,利用Webpack的代码分割功能(如异步加载、按需加载)来实现懒加载。这样可以减少初始加载时间,提升用户体验。 4. 优化图片:对于项目中的图片资源,可以使用压缩工具来减小图片大小,如使用imagemin-webpack-plugin等插件进行图片压缩。 5. 缓存和持久化:合理利用浏览器缓存和服务端缓存,减少不必要的请求和加载时间。另外,可以考虑使用localStorage或IndexedDB等技术进行数据持久化,减少数据加载时间。 6. 使用Tree Shaking:通过配置Webpack的tree shaking功能,可以剔除项目中未使用的代码,减少打包体积和提升加载速度。 7. 配置合理的Webpack:根据项目需求,合理配置Webpack的各项参数,如使用cache-loader、thread-loader等插件来提升构建速度。 需要注意的是,优化策略要根据具体项目情况进行选择,不同的项目可能有不同的瓶颈和优化空间。可以通过Webpack Bundle Analyzer等工具来分析打包结果,找出优化的重点。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值