当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

相关文章

详解Vue如何使用xlsx库导出Excel文件

《详解Vue如何使用xlsx库导出Excel文件》第三方库xlsx提供了强大的功能来处理Excel文件,它可以简化导出Excel文件这个过程,本文将为大家详细介绍一下它的具体使用,需要的小伙伴可以了解... 目录1. 安装依赖2. 创建vue组件3. 解释代码在Vue.js项目中导出Excel文件,使用第三

Oracle查询优化之高效实现仅查询前10条记录的方法与实践

《Oracle查询优化之高效实现仅查询前10条记录的方法与实践》:本文主要介绍Oracle查询优化之高效实现仅查询前10条记录的相关资料,包括使用ROWNUM、ROW_NUMBER()函数、FET... 目录1. 使用 ROWNUM 查询2. 使用 ROW_NUMBER() 函数3. 使用 FETCH FI

Java实现Excel与HTML互转

《Java实现Excel与HTML互转》Excel是一种电子表格格式,而HTM则是一种用于创建网页的标记语言,虽然两者在用途上存在差异,但有时我们需要将数据从一种格式转换为另一种格式,下面我们就来看看... Excel是一种电子表格格式,广泛用于数据处理和分析,而HTM则是一种用于创建网页的标记语言。虽然两

C#使用HttpClient进行Post请求出现超时问题的解决及优化

《C#使用HttpClient进行Post请求出现超时问题的解决及优化》最近我的控制台程序发现有时候总是出现请求超时等问题,通常好几分钟最多只有3-4个请求,在使用apipost发现并发10个5分钟也... 目录优化结论单例HttpClient连接池耗尽和并发并发异步最终优化后优化结论我直接上优化结论吧,

Java内存泄漏问题的排查、优化与最佳实践

《Java内存泄漏问题的排查、优化与最佳实践》在Java开发中,内存泄漏是一个常见且令人头疼的问题,内存泄漏指的是程序在运行过程中,已经不再使用的对象没有被及时释放,从而导致内存占用不断增加,最终... 目录引言1. 什么是内存泄漏?常见的内存泄漏情况2. 如何排查 Java 中的内存泄漏?2.1 使用 J

IDEA如何切换数据库版本mysql5或mysql8

《IDEA如何切换数据库版本mysql5或mysql8》本文介绍了如何将IntelliJIDEA从MySQL5切换到MySQL8的详细步骤,包括下载MySQL8、安装、配置、停止旧服务、启动新服务以及... 目录问题描述解决方案第一步第二步第三步第四步第五步总结问题描述最近想开发一个新应用,想使用mysq

java脚本使用不同版本jdk的说明介绍

《java脚本使用不同版本jdk的说明介绍》本文介绍了在Java中执行JavaScript脚本的几种方式,包括使用ScriptEngine、Nashorn和GraalVM,ScriptEngine适用... 目录Java脚本使用不同版本jdk的说明1.使用ScriptEngine执行javascript2.

Python 中 requests 与 aiohttp 在实际项目中的选择策略详解

《Python中requests与aiohttp在实际项目中的选择策略详解》本文主要介绍了Python爬虫开发中常用的两个库requests和aiohttp的使用方法及其区别,通过实际项目案... 目录一、requests 库二、aiohttp 库三、requests 和 aiohttp 的比较四、requ

Debian如何查看系统版本? 7种轻松查看Debian版本信息的实用方法

《Debian如何查看系统版本?7种轻松查看Debian版本信息的实用方法》Debian是一个广泛使用的Linux发行版,用户有时需要查看其版本信息以进行系统管理、故障排除或兼容性检查,在Debia... 作为最受欢迎的 linux 发行版之一,Debian 的版本信息在日常使用和系统维护中起着至关重要的作

SpringBoot项目启动后自动加载系统配置的多种实现方式

《SpringBoot项目启动后自动加载系统配置的多种实现方式》:本文主要介绍SpringBoot项目启动后自动加载系统配置的多种实现方式,并通过代码示例讲解的非常详细,对大家的学习或工作有一定的... 目录1. 使用 CommandLineRunner实现方式:2. 使用 ApplicationRunne