当vue遇到老的项目启动和打包速度慢怎么办? webpack-低版版本-编译启动速度和打包速度优化方案

本文主要是介绍当vue遇到老的项目启动和打包速度慢怎么办? webpack-低版版本-编译启动速度和打包速度优化方案,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

webpack优化背景

  • 前段时间我很幸运地接了一个古老的项目,webpack的版本还停留在4.0的版本,本来没想优化的,但是由于每次启动需要6分钟,保存一下页面热启动也需要2分钟,直接把我整崩溃了,这种心情 一言难尽
  • 我开发了一周,每天大概浪费2个小时在等待页面启动和编译上,我真的崩溃了
  • 于是我决定使用一天的时间优化webpack配置
  • 开始了我的优化之旅

优化成果

  • 第一次启动 10s
  • 热启动 5s 之内
  • 第一次打包 20s之内
  • 再次打包 10s之内

优化前提

  • 仔细阅读webpack的开发文档
  • 注意 很多api是只有webpack5的版本才支持的

优化的最大痛点

  • webpack 的版本过低(4.0),很多优秀的api和属性甚至是打包编译思想都没有用到

突如其来的一道灵光,换壳,将vue-cli3.6的版本直接升级到vue-cli5.0

  • 业务代码不变,改变项目的整体壳子和vue-clid等配置

可行性分析

业务代码影响分析

  • 都是vue项目并且vue的版本都是用的是vue2.6 的版本,所以业务代码是没有什么风险点的,唯一要改的是配置

配置代码分析

  • 由于vue-cli3.6升级到vue-cli5.0之后,webpack 的优秀属性就都可以使用了

升级vue-cli步骤

使用vue-cli5脚手架搭建一个空壳项目

  • 使用vue-cli5 搭建一个vue的基础项目

替换全局代码

替换业务代码

  1. 将src文件夹全部替换
  2. 将public 文件夹替换

package.json 修改

  1. 将vue-cli3.6老项目中的全局配置项和vue-cli5新壳子中的配置项目对比,把vue-cli5中出现过的依赖项直接删除,使用vue-cli5默认的
  2. 将vue-cli3.6老项目中出现的项目依赖项移捞出来放到新壳子中去
  3. 删除代码中没有引用的依赖项
  • 由于老项目中的依赖项可能是其他项目搬过来的,所以必定会出现没有用到的依赖项
  • 在代码中src文件夹下全局搜索,判断插件是否有使用到,没有用到的直接删除

.babelrc 文件修改

  • 由于vue-cli3.6和vue-cli5.0的babel处理方式不太一样,所以需要修改
  • 老的代码就不放了
vue-cli5的.babelrc代码
{"presets": ["@vue/cli-plugin-babel/preset"],"plugins": ["equire",["import",{"libraryName": "view-design","libraryDirectory": "src/components"}]]
}

修改vue.config.js

  • 壳子已经替换完毕,现在开始webpack 的配置

配置 vue.config.js

定义环境变量

const isDev = process.env.NODE_ENV == 'development'

transpileDependencies 关闭

  • 关闭之后,能够提编译速度
 transpileDependencies: isDev ? false : true,//转译依赖
  • 默认情况下 babel-loader 会忽略所有 node_modules 中的文件。你可以启用本选项,以避免构建后的代码中出现未转译的第三方依赖。

开启 terser-webpack-plugin 代码压缩

开启参数

  • minimize 开启压缩

TerserPlugin 配置

  • parallel 最大并行进程
  • cache 是否开启缓存
  • sourceMap 是否开启 sourceMap
  • terserOptions
    • compress 压缩选项
    • compress.drop_console 是否删除console 生产环境删除,开发环境保留
    • compress.drop_debugger 是否删除debugger 生产环境删除,开发环境保留
    • output.comments 是否删除comments 生产环境删除,,开发环境保留
let minimizeConfig = {                                            minimize: true,minimizer: [new TerserPlugin({parallel: 4,cache: true,sourceMap: false,terserOptions: {compress: {drop_console: isDev ? false : true,drop_debugger: isDev ? false : true,},output: {comments: false,},},})],concatenateModules: false, // 公共代码整合,生产环境下被启用
}

开启摇树优化

  • 将项目中重复的代码合并,删除多余的代码
config.optimization = {// runtimeChunk: true,usedExports: isDev ? false : true,//开启要数优化 tree shakingsideEffects: false,splitChunks: {chunks: 'all',minSize: 20000,minRemainingSize: 0,minChunks: 1,maxAsyncRequests: 30,maxInitialRequests: 30,enforceSizeThreshold: 50000,cacheGroups: {//公用模块抽离common: {chunks: 'initial',minSize: 0, //大于0个字节minChunks: 2, //抽离公共代码时,这个代码块最小被引用的次数},//第三方库抽离vendor: {priority: 1, //权重test: /node_modules/,chunks: 'initial',minSize: 0, //大于0个字节minChunks: 2, //在分割之前,这个代码块最小应该被引用的次数},default: {minChunks: 2,priority: -20,reuseExistingChunk: true}}}
}

watchOptions 忽略node_modules

config.watchOptions = {ignored: /node_modules/,//忽略node_modules包文件aggregateTimeout: 600,//多次修改批量更新poll: 1000//每秒检查一次变动
}

devtool配置

config.devtool = isDev ? 'source-map' : false//错误信息

开发环境

  • 启用sourcemap
  • devtool 设置值为 source-map

生产环境

  • 关闭sourcemap
  • 注意设置为false,否则无法彻底关闭sourcemap

开启cache缓存

  • 缓存是前端优化的常规手段,webpack 中同样可以
  • 缓存分内存和磁盘文件缓存,此处是使用文件磁盘缓存
    • type 使用 filesystem
    • allowCollectingMemory 收集在反序列化期间分配的未使用的内存,仅当 cache.type 设置为 ‘filesystem’ 时生效。这需要将数据复制到更小的缓冲区中,并有性能成本。
  • cacheDirectory 文件缓存的目录
    • 指定为档期目录下的 .temp_cache 文件夹下
    • 它下面分development 和 production 文件夹
config.cache = {type: 'filesystem',allowCollectingMemory: true,cacheDirectory: path.resolve(__dirname, '.temp_cache'),
}
  • 注意 建议定期删除 temp_cache 文件夹,以免占用过多磁盘空间
小伙伴担忧
是否会卡顿
  • 缓存太多是否会导致,内存爆掉甚至于卡顿
  • 我在此明确地告诉你,不会,原因很简单
    • 这个缓存是基于磁盘的,不是内存
    • 建议一周删除一次缓存文件

output 配置

      config.output = {clean: true, // 在生成文件之前清空 output 目录compareBeforeEmit: false,// 当在磁盘中已经存在有相同内容的文件时,webpack 将不会写入输出文件。filename: '[name].[contenthash].bundle.js',// wenpack打包后的文件名chunkFilename: 'js/[name].[contenthash].bundle.js',// 异步加载的模块path: path.join(__dirname, 'testProject'),publicPath: isDev ? '/' : '/testProject/',}

备注 chainWebpack 和 configureWebpack 区别

官方介绍

  • chainWebpack 是一个函数,会接收一个基于 webpack-chain 的 ChainableConfig 实例。允许对内部的 webpack 配置进行更细粒度的修改。
  • configureWebpack 如果这个值是一个对象,则会通过 webpack-merge 合并到最终的配置中

通俗区别

  • chainWebpack用于修改,会和默认配置项合并,追加某个属性值
  • configureWebpack用于合并,向原有配置项追加配置,直接添加整个配置项
  • 所以,只修改某个属性使用 chainWebpack,添加配置项使用configureWebpack

webpack辅助工具

  • 可帮助我我们更好的优化代码

webpack-bundle-analyzer

  • 代码分析工具,可分析打包之后的文件

speed-measure-webpack-plugin

  • 打包的速度分析,和时间分析插件
config.plugins.push(new BundleAnalyzerPlugin())
config.plugins.push(new WebpackBar({ name: 'PC', color: '#07c160' }))
const {defineConfig} = require('@vue/cli-service')
const TerserPlugin = require('terser-webpack-plugin');
const path = require('path')
const webpack = require('webpack');
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin
const resolve = dir => path.join(__dirname, dir)
const packageName = require('./package.json').name
const isDev = process.env.NODE_ENV == 'development'
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const WebpackBar = require('webpackbar');module.exports = defineConfig({// productionSourceMap: false, // 关闭生产环境的 source mappublicPath: isDev ? '/' : '/testProject/',outputDir: 'testProject',lintOnSave: false,transpileDependencies: isDev ? false : true,//转译依赖chainWebpack: config => {config.plugin('speed-measure-webpack-plugin').use(SpeedMeasurePlugin).end();if (!isDev) {config.plugins.delete('prefetch');// 移除 preload 插件config.plugins.delete('preload');}config.plugin('speed-measure-webpack-plugin').use(SpeedMeasurePlugin).end();},configureWebpack: config => {if (!isDev) {config.entry = "./src/main.js"                  config.output = {clean: true, // 在生成文件之前清空 output 目录compareBeforeEmit: false,// 当在磁盘中已经存在有相同内容的文件时,webpack 将不会写入输出文件。filename: '[name].[contenthash].bundle.js',// wenpack打包后的文件名chunkFilename: 'js/[name].[contenthash].bundle.js',// 异步加载的模块path: path.join(__dirname, 'testProject'),publicPath: isDev ? '/' : '/testProject/',// qiankun接入配置library: `${packageName}-[name]`,libraryTarget: 'umd', // 把微应用打包成 umd 库格式chunkLoadingGlobal: `webpackJsonp_${packageName}`,//webpack5 output.jsonpFunction 更名为 output.chunkLoadingGlobal}config.plugins.push(new BundleAnalyzerPlugin())config.plugins.push(new WebpackBar({ name: 'PC', color: '#07c160' }))}config.resolve.alias =// 设置路径别名,设置后需保持jsconfig.json内一致{'@': resolve('src'),'_c': resolve('src/components')}let minimizeConfig = {                                            minimize: true,minimizer: [new TerserPlugin({parallel: 4,cache: true,sourceMap: false,terserOptions: {compress: {drop_console: isDev ? false : true,drop_debugger: isDev ? false : true,},output: {comments: false,},},})],concatenateModules: false, // 公共代码整合,生产环境下被启用}config.optimization = {// runtimeChunk: true,usedExports: isDev ? false : true,//开启要数优化 tree shakingsideEffects: false,splitChunks: {chunks: 'all',minSize: 20000,minRemainingSize: 0,minChunks: 1,maxAsyncRequests: 30,maxInitialRequests: 30,enforceSizeThreshold: 50000,cacheGroups: {//公用模块抽离common: {chunks: 'initial',minSize: 0, //大于0个字节minChunks: 2, //抽离公共代码时,这个代码块最小被引用的次数},//第三方库抽离vendor: {priority: 1, //权重test: /node_modules/,chunks: 'initial',minSize: 0, //大于0个字节minChunks: 2, //在分割之前,这个代码块最小应该被引用的次数},default: {minChunks: 2,priority: -20,reuseExistingChunk: true}}}}if (!isDev) {config.optimization = Object.assign(config.optimization, minimizeConfig)console.log(config.module)}config.watchOptions = {ignored: /node_modules/,//忽略node_modules包文件aggregateTimeout: 600,//多次修改批量更新poll: 1000//每秒检查一次变动}config.devtool = isDev ? 'source-map' : false//错误信息config.cache = {type: 'filesystem',allowCollectingMemory: true,cacheDirectory: path.resolve(__dirname, '.temp_cache'),}}
})

优化成果

初次 npm run dev 运行速度

  • 所有的缓存文件都清除,运行时间大概在36秒
    在这里插入图片描述

基于缓存 npm run dev 运行速度

  • 只需要 4.7秒
    在这里插入图片描述

初次 npm run build 打包速度

在这里插入图片描述

基于缓存 npm run build 打包速度

  • 9.64秒

在这里插入图片描述

项目体量

src文件数量和大小

  • 770个文件,10MB
    在这里插入图片描述

项目依赖大小

  • 781MB
    在这里插入图片描述

打包后文件 大小

  • 仅有 9.8MB
    在这里插入图片描述

个人总结

  • webpack 本质上也是js,我们不会配置,可能只是不太熟悉,不要有恐惧心理
  • 先看仔细阅读文档,重点看他的优化方案,整合下即可结合到项目中

致谢

  • 感谢webpack官方文档提供的文档说明
  • 感谢我的项目组给了我挑战自己的机会
  • 感谢我的导师给予我的帮助

  • 感谢您百忙之中抽时间阅读我写的博客,谢谢您的肯定,也希望对您能有所帮助
  • 如果您有更好的见解请在评论区留言或者私聊我,期待与您的交流

这篇关于当vue遇到老的项目启动和打包速度慢怎么办? webpack-低版版本-编译启动速度和打包速度优化方案的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/754346

相关文章

MyBatis Plus实现时间字段自动填充的完整方案

《MyBatisPlus实现时间字段自动填充的完整方案》在日常开发中,我们经常需要记录数据的创建时间和更新时间,传统的做法是在每次插入或更新操作时手动设置这些时间字段,这种方式不仅繁琐,还容易遗漏,... 目录前言解决目标技术栈实现步骤1. 实体类注解配置2. 创建元数据处理器3. 服务层代码优化填充机制详

防止Linux rm命令误操作的多场景防护方案与实践

《防止Linuxrm命令误操作的多场景防护方案与实践》在Linux系统中,rm命令是删除文件和目录的高效工具,但一旦误操作,如执行rm-rf/或rm-rf/*,极易导致系统数据灾难,本文针对不同场景... 目录引言理解 rm 命令及误操作风险rm 命令基础常见误操作案例防护方案使用 rm编程 别名及安全删除

Vue和React受控组件的区别小结

《Vue和React受控组件的区别小结》本文主要介绍了Vue和React受控组件的区别小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录背景React 的实现vue3 的实现写法一:直接修改事件参数写法二:通过ref引用 DOMVu

Python实现批量CSV转Excel的高性能处理方案

《Python实现批量CSV转Excel的高性能处理方案》在日常办公中,我们经常需要将CSV格式的数据转换为Excel文件,本文将介绍一个基于Python的高性能解决方案,感兴趣的小伙伴可以跟随小编一... 目录一、场景需求二、技术方案三、核心代码四、批量处理方案五、性能优化六、使用示例完整代码七、小结一、

Java实现将HTML文件与字符串转换为图片

《Java实现将HTML文件与字符串转换为图片》在Java开发中,我们经常会遇到将HTML内容转换为图片的需求,本文小编就来和大家详细讲讲如何使用FreeSpire.DocforJava库来实现这一功... 目录前言核心实现:html 转图片完整代码场景 1:转换本地 HTML 文件为图片场景 2:转换 H

C#使用Spire.Doc for .NET实现HTML转Word的高效方案

《C#使用Spire.Docfor.NET实现HTML转Word的高效方案》在Web开发中,HTML内容的生成与处理是高频需求,然而,当用户需要将HTML页面或动态生成的HTML字符串转换为Wor... 目录引言一、html转Word的典型场景与挑战二、用 Spire.Doc 实现 HTML 转 Word1

Vue3绑定props默认值问题

《Vue3绑定props默认值问题》使用Vue3的defineProps配合TypeScript的interface定义props类型,并通过withDefaults设置默认值,使组件能安全访问传入的... 目录前言步骤步骤1:使用 defineProps 定义 Props步骤2:设置默认值总结前言使用T

Vite 打包目录结构自定义配置小结

《Vite打包目录结构自定义配置小结》在Vite工程开发中,默认打包后的dist目录资源常集中在asset目录下,不利于资源管理,本文基于Rollup配置原理,本文就来介绍一下通过Vite配置自定义... 目录一、实现原理二、具体配置步骤1. 基础配置文件2. 配置说明(1)js 资源分离(2)非 JS 资

使用Python实现Word文档的自动化对比方案

《使用Python实现Word文档的自动化对比方案》我们经常需要比较两个Word文档的版本差异,无论是合同修订、论文修改还是代码文档更新,人工比对不仅效率低下,还容易遗漏关键改动,下面通过一个实际案例... 目录引言一、使用python-docx库解析文档结构二、使用difflib进行差异比对三、高级对比方

Three.js构建一个 3D 商品展示空间完整实战项目

《Three.js构建一个3D商品展示空间完整实战项目》Three.js是一个强大的JavaScript库,专用于在Web浏览器中创建3D图形,:本文主要介绍Three.js构建一个3D商品展... 目录引言项目核心技术1. 项目架构与资源组织2. 多模型切换、交互热点绑定3. 移动端适配与帧率优化4. 可