• 作者:老汪软件技巧
  • 发表时间:2024-10-16 10:03
  • 浏览量:

背景

我们团队的项目一直是使用 vite 作为打包工具的,由于 vite 开发环境和生产环境的打包策略不同(开发环境按需打包,生产环境全量打包),所以存在开发环境和线上环境打包产物表现不一致的风险。其 css 样式不一致的问题尤为容易发生,目前在需求开发过程中,已多次遇到本地开发环境 css 样式符合 UI 稿,发布到测试环境或者线上之后就出现了差异的场景。

基于上述背景,我们期望迁移至一款开发和生产环境打包产物一致的工具。

方案调研

除上述背景外,我们期望的打包工具还应该满足以下特性:

要满足打包性能优异的特性,除 vite 外,我们的打包工具范围最终锁定在由 rust 开发项目内:

TurbopackFarmRsbuild(基于rspack)

产物一致性

❌ 不一致

✅ 一致

✅ 一致

打包性能

✅ 快

✅ 快

✅ 快

生态及稳定性

❌ 全新生态,生态链较差

✅ 兼容 vite 插件(先试验了下 farm,遇到的坑太多了且解决不了,根据 github 的用户数以及 npm 下载量,感觉目前尚未达到稳定可用状态)

✅ 兼容 webpack 插件且已有众多线上项目验证

迁移成本

(没有对应的插件)

❌ 高(踩坑太多且无解决思路,应该是farm本身的坑)

✅ 中

经过调研和实践,最终选定 rsbuild 作为最终的工具。

最终收益

流水线构建时长:360s 左右 > 130s 左右,减少 150%(整条流水线上除了打包之外,还有拉代码仓库、代码质量检测、安装依赖、上传 CDN 等其他工作,而构建工具只是减少了打包这一阶段的工作时长,但打包依然是占最大头的,所以收益还是很明显)

冷启动时长:

可以看到首屏冷启动时长性能有比较大的劣化,这是因为 vite 是根据页面按需资源打包,而 rsbuild 是全量打包。(但全量打包目前应该是解决开发和生产产物不一致的必要条件,为解决我们的背景问题必不可少)

冷启动时长综合对比,如果在开发过程中切换页面比较多的话,最终的等待时长 rspack 会胜于 vite;如果只关注于一个页面的开发,vite 这方面占优

热更新:0.5s 内 > 1.5s 内(都是很低的数值,体感没有差别)

_前端移动端项目整体流程_前端怎么转型产品

资源分包数:以我们项目的首屏为例,可以看到 rsbuild 的分包策略要由于 vite(打包总体积几乎无变化的情况下,分包数少了很多):

迁移过程及踩坑安装相关依赖

安装 rsbuild 核心包:

yarn add @rsbuild/core @rsbuild/plugin-babel @rsbuild/plugin-less @rsbuild/plugin-sass @rsbuild/plugin-vue @rsbuild/plugin-vue-jsx -D

其他插件根据自己项目的需要进行安装,可以在 rsbuild 官网找到。常用的有:

@rsbuild/plugin-babel
@rsbuild/plugin-less
@rsbuild/plugin-sass
@rsbuild/plugin-vue
@rsbuild/plugin-vue-jsx

更改打包配置文件

下面是以我们的项目为例(一些敏感代码没有在上面展示),将 vite.config.ts 迁移到 rsbuild.config.ts ,可以进行参考:

修改对应指令

// package.json
{
  "scripts": {
    "dev": "rsbuild dev",
    "build": "rsbuild build",
    "preview": "rsbuild preview",
    // others...
  },
  // ...others
}

修改 index.html

移除掉 index.html 之前的 引入代码。

踩坑import.meta 不兼容

import.meta 是浏览器 module 模块中独有的语法,rsbuild 在 rsbuild.config.js 中可以使用 import.meta,但是在项目源代码中并不支持,所以我们需要对原本代码中的 import.meta 进行适配。

以我们项目为例,大部分代码中的 import.meta.XXX 都是在本地的 .env.local 文件中定义的,我们可以借助 source.define 去进行全局的声明:

import { defineConfig } from '@rsbuild/core';
const { VITE_APP_HOST } = import.meta.env;
export default defineConfig(({ env }) => ({
    source: {
        define: {
            'import.meta.env.VITE_APP_HOST': `'${VITE_APP_HOST}'`,
        },
    },
}));

另外我们项目还用到了 import.meta.url 去引入资源,这种需要改为 import 方式去引入:

// 改之前:
const href = new URL('../assets/icon.png', import.meta.url).href;
// 改之后:
import IconPNG from '../assets/icon.png';
const href = IconPNG;

:deep 和 & 兼容问题

目前已知 @rsbuild/plugin-less 插件对于在 :deep 内部使用 less 的 & 符号会有问题,例如:

.container {
    .content {
        &_title {
            font-weight: bold;
        }
    }
}

.container {
    :deep(.content) {
        .content_title {
            font-weight: bold;
        }
    }
}

.container {
    :deep(.content) {
        &_title {
            font-weight: bold;
        }
    }
}

后面会去 github 提个 issue,我们项目内部这种使用情况很少,所以暂时手动修改为不使用 &。

css 中使用 v-bind 不支持三元运算符

不支持在 css 中 v-bind 使用三元运算符,可以改成在 js 中使用三元运算符替代

// 改之前:
.container {
  height: v-bind(title ? '24px' : '48px');
}
// 改之后:
const containerHeight = title ? '24px' : '48px'; // js中写
.container {
  height: v-bind(containerHeight);
}

结论

我们的项目目前有 2500+ 文件、30w+ 行代码,算是一个很大的项目了。对于这样一个大型项目而言,从 vite 迁移 rsbuild 的过程中遇到的坑可以算很少了,而且迁移后的收益很明显,足以证明 rsbuild 及 rspack 是一个十分优秀的项目,且完全可以在生产环境中去应用了。

对于 webpack 构建的项目,我相信收益会更加明显,有折腾想法的朋友可以年底迁移一波作为 KPI 试试

最后的最后,快手基础平台团队招前端,欢迎在平台私信我投简历~


上一条查看详情 +nginx使用小记
下一条 查看详情 +没有了