当前位置: 首页 > news >正文

vue-cli项目升级rsbuild,效率提升50%+

项目中有上千个页面,原有的脚手架vue-cli打包时间需要好几分钟。开发时改个文件等待编译时间长,严重影响了开发效率。

为了提升开发效率以及缩短打包时间,在viterspack中,最终选择了rspackrspack是webpack的平替,它兼容webpack的插件,迁移心智负担低。目前rspack版本是1.3

官网提供了基本的迁移,可以参考vue-cli 迁移

vue2 插件版本仅支持>=2.7.0版本,可以直接升级vue版本到最新的2.7.16

迁移之路 {#migrate-road}

迁移之路真是一波三折,在rspack版本为0.6的时候就尝试过了,当时测试的编译时间比vue-cli快很多,但是当时功能可能不太完善,有些bug实在是改不动了,便搁置了。这在文章里有所体现,文章里有些问题当时记录了现在没有删除,只是记录仅供查看。

而且间隔这么长时间,之间项目开发的页面文件较之前又增加了很多,期间我没参与这个项目的开发,也就没管。现在又开始接触这个项目了,发现开发启动和打包编译时间都很长。这我不能忍😤

项目的初始配置为vue-cli@3及相关配置,现在的vue-cli版本最新已经是5.0.8了。按照我电脑的性能mac来对比编译时间,相比同事windows的电脑编译时间则会更长。

在初始项目配置vue-cli@3配置下,我的编译时间为1m20s 多,同事电脑上则会有5m多。升级到rspack最新版本1.3.17,升级之路还好,遇到的问题基本记录在案了。当时满心欢喜的把配置也拉满了,心想这升级后性能提升虽不能翻倍,但编译时间提升肯定甩它个几条街。事实被打脸了😭

升级完之后我电脑的平均编译时间为3m30s. 我整个人都不好了,为什么啊?😳 还好当时开发环境有配置按需编译,这一点让我没有立马扔掉rspack进行回退。

export default defineConfig({dev: {lazyCompilation: true},
})

然后就是各种翻阅文档,查看各种优化手段,尝试并减配,但编译时间仍不能提升上来,抱着不放弃的态度,在dicussion提了问题,当然也没抱什么希望,觉得短时间也不会有人回复,如果第二天不能得到解决,我就回退了,像是下定了某种决心🙃。
在这里插入图片描述

没想到得到了大佬的回复,然后根据大佬的提示进行性能分析https://rsbuild.dev/zh/guide/debug/build-profiling , 得知了rspack编译时rust侧时间消耗在2m左右,因为这段在时序图里时空白的,所以看不到什么。其它时间消耗在vue-loader上,对于js侧消耗时间其实能接受,减掉这2分钟,编译时间和之前差不多持平。

于此同时我在rstack交流群里也发布了同样的问题,看大家是否遇到同样的问题,群里大佬也回复让我使用性能分析,使用了rsdoctor工具分析时遇到功能无法使用,大佬说我的项目文件太大了,他们会继续优化该问题,到此问题并没有得到解决,只能等到第二天准备回退到vue-cli了。

为了保留升级后的配置信息,拉了新的分支,以便后续问题解决后再升级。并准备升级vue-cli到最新版本5.0.8,想的是怎么着升级之后性能虽不能有大的提升,但也应该有所提升吧。现实又是狠狠的打了我一巴掌😣

在所有的依赖升级完成之后,满心欢喜的开始编译构建,随着等待时间,心一下子凉了。怎么个事啊,MLBZD 😤 编译时间足足翻了一倍3m40s,平均都快到5m多,这还是我的电脑上,那同事电脑上岂不是炸了。

没事没事,谁让我爱折腾呢,只能心里安慰了,然后反复在vue-cli@3vue-cli@5测试了多次编译时间后,我明白了升级并不一定能带来编译时间的提升,升级之后还带来了依赖包尺寸增大的问题,功能多了编译时间自然也就长了。

在我快要放弃了的时候(心想搞这升级干嘛,吃饱了撑的),此时群里有大佬回复了,我仿佛看到了曙光,他说可以尝试rsbuild@1.2版本,他们在升级之后速度是有提升的,但是升级rspack@1.3版本后会有降速的问题,所以建议不要使用版本1.3.

Ok,我这人听劝,迫不及待的就降级版本到1.2.19,并且阅读了版本1.3的发布公告,发现对我的配置并没有影响,配置优化暂时可以不在乎,可以直接使用。调整完之后,怀着忐忑的心执行npm run build,期待奇迹的发生,果然编译速度提升到了一个不可置信的高度,重新编译计时 50s,至此悬着的心终于放心了,给大佬点赞,给rsbuild点赞,给rspack点赞.

让同事测试了编译时间为2m20s左右,比之前的编译时间缩短了一半。

升级之后不仅得到编译速度的提升,对于一些依赖也升级到了最新版本,带来了新功能,更能助力我们开发,提升开发效率。

好了,下面是vue-clirsbuild升级需要修改的配置。安心享用吧😉

迁移配置

移除vue-cli依赖,安装rsbuild的依赖

移除vue-cli相关依赖@vue/*

 npm remove @vue/cli-service @vue/cli-plugin-babel @vue/cli-plugin-eslint core-js

可以先移除与babel相关的所有依赖,后续再根据错误信息步步添加配置。

可以顺手把其他功能依赖版本升级到minor版本最新。如果你对其它依赖主版本比较了解,则可以升级到最新版本。
在这里插入图片描述

安装rsbuild的依赖,并且需要支持vue / jsx,安装相关依赖,我们的项目是vue2的

 npm add @rsbuild/core @rsbuild/plugin-vue2 @rsbuild/plugin-vue2-jsx @rsbuild/plugin-babel  -D

删除掉原来的配置文件vue.config.js,新建rsbuild配置文件rsbuild.config.js

  • 支持jsx,需要安装@rsbuild/plugin-vue2-jsx @rsbuild/plugin-babel

  • html.template 配置模板,指向./public/index.html

  • 增加source.alias配置路径别名,对应的是rspack中的resolve.alias

  • 修改package.json中的脚本部分,移除掉vue-cli-service 该用rsbuild

    {"scripts": {"dev": "rsbuild dev","build": "rsbuild build","lint": "eslint --ext .js,.jsx,.vue ./src"}
    }
    

    rsbuil 不包含lint,所以直接使用eslint

基本的迁移配置rsbuild.config.js

import { defineConfig } from "@rsbuild/core";
import { pluginVue2 } from "@rsbuild/plugin-vue2";
import { pluginBabel } from "@rsbuild/plugin-babel";
import { pluginVue2Jsx } from "@rsbuild/plugin-vue2-jsx";
const path = require("path");export default defineConfig({plugins: [pluginVue2(),pluginBabel({include: /\.(?:js|jsx|tsx)$/,exclude: /[\\/]node_modules[\\/]/,}),pluginVue2Jsx(),],html: {template: "./public/index.html",},source: {// 指定入口文件entry: {index: "./src/main.js",},alias: {"@": path.resolve(__dirname, "./src"),},},
});

html模板中的变量<%= BASE_URL %>变更为<%= assetPrefix %>/

- <link rel="icon" href="<%= BASE_URL %>logo.png" />+ <link rel="icon" href="<%= assetPrefix %>/logo.png" />

less\sass通过插件配置实现, 移除掉了已安装的依赖

 npm remove less less-loader sass sass-loader

安装相关插件,并在配置rsbuild.config.js中使用插件。

npm add @rsbuild/plugin-less @rsbuild/plugin-sass -D

在迁移之路 中我们使用了rsbuild的低版本1.2,所以这里less \ sass的版本我们也降级。@rsbuild/plugin-less@1.1.1@rsbuild/plugin-sass@1.2.2

插件包含的less、sass版本默认是最新的,如果存在深度依赖某个版本的功能,可以安装指定版本并通过配置插件配置项,

export default defineConfig({plugins: [pluginLess({lessLoaderOptions: {implementation: require("less"),},}),]
})

安装指定的less版本,对于sass也是一样的,可指定版本安装。

npm add less@3 -D

vue文件里的scoped样式穿透时使用的/deep/不生效了,但是查看了vue插件vue-loader没说不支持,修改为::v-deep 就可以了。

问了社区为什么不支持,/deep/废弃了,它不是标准的css语法。https://github.com/rspack-contrib/rsbuild-plugin-vue2?tab=readme-ov-file#faq

引用静态资源,比如图片 (这个问题已经不存在了)

除了相对目录引入之外../../assets/test.png,可以通过路径别名@ 来访问,也就是@/assets/test.png

遇到一个问题就是如果一个 less 中引入资源图片,在另一个 less 文件中导入这个文件,就会出现图片资源加载不到的问题

@import "../../base.less";// ...

这样就会导致base.less中的图片引入地址~@/assets/test.png 变为../../~@/assets/test.png 导致加载不到。感觉这应该是一个 bug 🤔。

~开头是 vue-cli 的资源转换规则,它会将这个内容作为一个模块请求解析。~@则会请求获取路径别名@下指定的资源。

为了批量处理,写一个解析 loader 将~@改为@

一个解决方案就是不要在样式文件中导入另一个样式文件,可以在 js 文件中导入 less 文件。

还有 less 文件变量的问题,可以将全局的变量声明放到一个 less 文件variables.less. 配置为全局引入。

这个修改的工作量还是很大的 😢 需要修改所有引用变量文件的地方。

修改配置,增加 less 配置,全局注入变量

export default defineConfig({// ...tools: {less: {additionalData: '@import "@/variables.less";',},},
});

内置了postcss,内置了autoprefixer

移除掉本地依赖,可以通过tools.postcss进行配置,当然也可以通过外部配置文件postcss.config.js自定义配置;

npm remove postcss autoprefixer

这个是在rsbuild版本为0.6时的问题,现在新版本没有问题了。仅供查看

rsbuild 内置的 postcss 版本是最新的v8,通过postcss.config.js配置的插件编译不能通过
在这里插入图片描述

对于引入的插件 postcss 插件postcss-px-to-viewport构建错误,提示不存在方法,就去查看了插件有没有更新。发现好久没更新了,就按照错误提示看看插件怎么更新

Why do I need to update my plugin?

还好,需要改动的地方还算清晰,直接上手修改了。在node_modules找到这个包找到入口文件,修改文件

  • postcss 移到 peerDependencies 里面
  • 使用module.exports = creator代替module.exports = postcss.plugin(name,creator)
  • 原来返回一个函数,现在返回一个对象,包含配置属性、各个钩子函数调用。
  • css.walkRules 改为调用Once()
  • 最后加上module.exports.postcss = true
// module.exports = postcss.plugin('postcss-px-to-viewport', function (options) {
module.exports = (options = {}) => {// return function (css) {//   css.walkRules(function (rule) {return {postcssPlugin: 'postcss-px-to-viewport',Once(root, { result }){root.walkAtRules(function (rule) {// ...}}}
}module.exports.postcss = true

修改完之后,为了保证其他同事可用。通过patch-package生成一个补丁包,并提交自己的修改。

 npx patch-package postcss-px-to-viewport

再次启动运行,不再有错误提示了。

@rsbuild/plugin-node-polyfill node polyfill 插件

项目中存在依赖使用 node 模块,使用该模块将 node 核心模块注入到浏览器端。

 npm i @rsbuild/plugin-node-polyfill -D

增加配置,作为插件使用:

import { pluginNodePolyfill } from "@rsbuild/plugin-node-polyfill";export default defineConfig({plugins: [//...pluginNodePolyfill(),],
});

可以通过配置globals来指定需要注入模块的 polyfill

支持.md文件解析,安装url-loader

安装 webpack 的插件url-loader

 npm i url-loader

增加配置,指定加载资源的 loader , 通过tools.rspack针对 rspack 增加底层配置。

export default defineConfig({// ...tools: {rspack(config, { addRules }) {addRules([{test: /\.md$/,loader: "url-loader",},]);},},
});

@rsbuild/plugin-eslint 运行 eslint 检查

移除掉旧的 eslint 的相关依赖:

npm remove eslint eslint-plugin-vue @vue/eslint-config-standard

对于还用到的依赖,顺便可以重新安装进行升级:

npm i -D @rsbuild/plugin-eslint eslint-plugin-vue vue-eslint-parser eslint-config-prettier globals @eslint/js

eslint@9推荐配置文件名称为eslint.config.[c|m]js,我们使用配置文件eslint.config.mjs

import PluginVue from "eslint-plugin-vue";
import PluginPrettier from "eslint-config-prettier";
import js from "@eslint/js";
import globals from "globals";
import VueParser from "vue-eslint-parser";export default [js.configs.recommended,...PluginVue.configs["flat/vue2-recommended"],PluginPrettier,{languageOptions: {globals: {...globals.browser},parser: VueParser,parserOptions: {sourceType: "module",ecmaFeatures: {jsx: true,},},},rules: {// ...},},
];

@rsbuild/plugin-eslint 作为插件配置到rsbuild.config.js中,可以通过配置项enable控制是否开启eslint检查。我们启用了eslint@9的flat config;支持.vue文件检查,增加后缀。

import { pluginEslint } from "@rsbuild/plugin-eslint";export default defineConfig({plugins: [//...pluginEslint({enable: true,eslintPluginOptions: {cwd: __dirname,configType: "flat",extensions: ["js", "jsx", "vue"],},}),],
});

启动后,发现很多规则检查的代码问题;太多了挨个改不太现实,将这些规则改为警告级别。

由于性能问题,编译时检查代码会导致编译时间过长,建议不开启eslint.可以单独执行npm run lint检查代码。

transpileDependencies 配置调整为include

一些存在于node_modules的第三方模块需要编译时,需要的配置。

{source: {// ...include: [/[\\/]node_modules[\\/]custome-component[\\/]/,],},
}

项目中还使用了svg-sprite-loader

插件的作用可以去查看在 vue 项目中配置使用 svg

配置方式基本没有变,通过tools.bundlerChain来修改添加 loader

export default defineConfig({bundlerChain(chain, { CHAIN_ID }) {// 修改原svg加载的方式,排除掉需要作为图标使用的svg目录chain.module.rule(CHAIN_ID.RULE.SVG).exclude.add(path.join(__dirname, "./src/assets/svgs"));// 增加一条svg的loader,只处理指定目录chain.module.rule("svg-sprite-loader").test(/\.svg$/).use("svg-sprite-loader").loader("svg-sprite-loader").options({ symbolId: "icon-[name]" }).end().include.add(path.join(__dirname, "./src/assets/svgs")).end();},
});

优化

rsbuild 默认提供了一些优化配置,可以减少开发时编译的模块数量,提高编译速度。

性能分析

https://rsbuild.dev/zh/guide/debug/build-profiling 子这里提供了性能分析的方法,官方提供了rsdoctor插件,制定了一些规则,loader分析、plugin分析可以很好的查看编译时间消耗在哪里,针对性调整。

npm i @rsdoctor/rspack-plugin -D

rsbuild.config.js增加配置,在标识需要分析时才执行,因为分析也会加大编译时间

import { RsdoctorRspackPlugin } from "@rsdoctor/rspack-plugin";export default defineConfig({tools: {rspack(config, { addRules, appendPlugins }) {if (process.env.RSDOCTOR === "true") {appendPlugins(new RsdoctorRspackPlugin({mode: "brief",reportCodeType: {noAssetsAndModuleSource: true,},}));}}}
})

这样我们增加脚本配置环境变量,可以选择执行脚本来分析构建

{"scripts": {"dev": "rsbuild dev","build:perf": "NODE_OPTIONS=--max_old_space_size=12288 RSDOCTOR=true rsbuild build","build": "rsbuild build","lint": "eslint --quiet --ext .js,.jsx,.vue ./src "},
}

如果项目太大,内存可能不够会报错,配置增加NODE_OPTIONS=--max_old_space_size=12288.

配置Lazy Compilation 减少开发时编译的模块数量

可以明显看到启动时间减少。

export default defineConfig({dev: {lazyCompilation: true,// 展示编译进度条progressBar: true,},
})

使用图片压缩

安装插件@rsbuild/plugin-image-compress启用图片压缩功能。

import { pluginImageCompress } from "@rsbuild/plugin-image-compress";export default defineConfig({plugins: [pluginImageCompress()],
})

拆包

rsbuild 已经默认了拆包规则split-by-experience按照经验制定的一些拆分策略,比如polyfill \ lodash \ axios等,还可以自定义将一些依赖拆分。充分利用浏览器的缓存机制,减少请求数量,加快页面加载速度。

export default {performance: {chunkSplit: {strategy: 'split-by-experience',forceSplitting: {echarts: /node_modules[\\/]echarts/,elementUi: /node_modules[\\/]element-ui/,},},},
};

还有一些其他的拆包策略:

  • split-by-module 按照npm包拆分,每个npm依赖是一个chunk。
  • split-by-size 按照体积大小自动拆分。
  • all-in-one 将所有代码大包到一个chunk中。
  • single-vendor 将所有npm依赖包打到一个chunk中。
  • custom 自定义拆分。

rsbuild 支持动态导入拆包,dynamic import是es 2020新特性,可以动态加载js模块,rsbuild会将它们拆分为单独的chunk。

启用Lightning CSS

Lightning CSS 是一个基于 Rust 编写的高性能 CSS 解析、转译和压缩工具.

import { pluginLightningcss } from '@rsbuild/plugin-lightningcss';export default {plugins: [pluginLightningcss()],
};

静态资源内联

将一些静态资源内联到html或js中,减少请求次数。比如图片、视频、css文件等。

开启内联css到html中

export default {output: {inlineStyles: true,},
};

对于内联资源,可以将一些小体积的资源选择性内联,内联资源会增加包的体积,增加了加载时间。而且内联资源不利于缓存,不能重复使用。

http://www.xdnf.cn/news/446869.html

相关文章:

  • 文章记单词 | 第74篇(六级)
  • uniapp设置 overflow:auto;右边不显示滚动条的问题
  • 多线程与线程互斥
  • PROE 转 STP 全攻略:软件实操、在线转换与问题解决
  • 学习日志06 java
  • 辛格迪客户案例 | 碧博生物实施用友ERP(U8)系统,同步开展计算机化系统验证(CSV)
  • 数学建模初等模型应用
  • ai agent(智能体)开发 python3基础16:通过最基本的request,json连链接本地模型 ollama中的deepseek-r1:8b
  • 高压差分探头CMRR性能评估方法及优化策略
  • 微服务如何实现服务的高可用
  • html js 原生实现web组件、web公共组件、template模版插槽
  • 【嵌入式开发-软件定时器】
  • Java内存马的检测与发现
  • GraphPad Prism简介、安装与工作界面
  • 【软件测试】第二章·软件测试的基本概念
  • 二叉树前序与后序遍历迭代法详解:栈操作与顺序反转的巧妙结合
  • NVMe简介1
  • Android 中 图片加载库 Glide 简介
  • 【Java-EE进阶】SpringBoot针对某个IP限流问题
  • Protocol Buffers 全流程通俗讲解
  • vLLM - SamplingParams 参数
  • 【BUG】滴答定时器的时间片轮询与延时冲突
  • 力扣热题——找出 3 位偶数
  • 康谋分享 | 自动驾驶仿真进入“标准时代”:aiSim全面对接ASAM OpenX
  • C++类和对象--高阶
  • 猫眼浏览器:简约安全,极速浏览
  • 基于多目标进化算法的神经网络架构搜索及其高级可视化技术
  • Huffman树
  • 常用的Java工具库
  • 错误: 加载主类 org.springframework.boot.loader.launch.JarLauncher 时出现 LinkageError