点击围观!腾讯 TAPD 助力金融行业研发提效、敏捷转型最佳实践! 了解详情
写点什么

使用 Rspack 构建真实开源项目,实测迁移成本和性能收益

  • 2023-04-13
    北京
  • 本文字数:4321 字

    阅读完需:约 14 分钟

使用 Rspack 构建真实开源项目,实测迁移成本和性能收益

在上个月,字节跳动开源了基于 Rust 的新一代构建引擎 Rspack,对 webpack 的 API 保持良好的兼容性,同时带来 5~10 倍的性能提升:

官网文档: https://www.rspack.dev/


这篇文章我们不妨用一个开源项目来实测一下,这里选取一个非常流行的绘图软件 exclidraw,实际上它们的源码都是用 TS 写的,并且是开源的,整体通过 create-react-app 来进行搭建。

exclidraw:https://excalidraw.com/ 

exclidraw 开源:https://github.com/excalidraw/excalidraw


接下来,我们就来一步步将这个复杂的开源项目接入到 Rspack,看看最后效果如何。当然,你也可以跟着一步步进行操作,实际体验下迁移前后的差异。

拉取 exclidraw 项目仓库


首先你需要将代码拉取下来:

git clone git@github.com:excalidraw/excalidraw.git
复制代码


OK,我们首先安装依赖并且启动项目:

yarn yarn start
复制代码


你可以发现如下的界面:

说明项目已经正常启动起来了。接下来我们来一步步接入 Rspack。

初始化 Rspack


我们先安装 @rspack/cli:

yarn add @rspack/cli
复制代码


然后配置入口:

  • package.json

{  "scripts": {    "build:rspack": "rspack build",    "start:rspack": "rspack serve"  },  "dependencies": {     "@rspack/cli": "0.1.4"  }}
复制代码
  • rspack.config.js

module.exports = {   context: __dirname,   entry: {     main: './src/index.tsx'   }}
复制代码


除此之外,我们还需要梳理一下要搭建这个项目的构建工作流需要考虑哪些因素:

  • Sass 配置。因为项目中使用了 Sass 语法,我们需要添加相应配置。

  • HTML 插件。在传统的 webpack 项目中,我们一般用 html-webpack-plugin 来处理 html,将 css、js 的内容插入到 html 中,并处理一些模板变量。那么在 Rspack 中也不例外,官方提供 @rspack/plugin-html 这一平替方案。

  • dotenv 的配置。你可以注意到项目根目录存在.env.development 这样的环境变量文件,在构建流程中我们需要通过对应的工具来读取这些文件。

html-webpack-plugin:https://www.npmjs.com/package/html-webpack-plugin


好,接下来,我们来一步步进行操作。

完善 Rspack 工作流

Sass 编译配置


我们安装下 sass-loader 并加上 sass 相关的配置。

  • package.json

{  "dependencies": {       "sass-loader": "13.2.2"   }}
复制代码
  • rspack.config.js

module: {    rules: [      {        test: /\.scss$/,        use: [          {            loader: "sass-loader",          },        ],        type: "css",      },    ],  },
复制代码


Rspack 内置了对 css 的支持,因此我们这里只需要配置type: 'css'即可,而不需要使用 css-loader。

HTML 插件配置


现在你可以尝试运行pnpm start:rspack,结果正常编译了, 我们再检查下产物,访问 http://localhost:8080/


结果我们发现如下的报错:

URIError: Failed to decode param '/%REACT_APP_CDN_MATOMO_TRACKER_URL%'    at decodeURIComponent (<anonymous>)    at decode_param (/Users/xxx/excalidraw/node_modules/@rspack/dev-server/node_modules/webpack-dev-server/node_modules/express/lib/router/layer.js:172:12)    at Layer.match (/Users/xxx/project/excalidraw/node_modules/@rspack/dev-server/node_modules/webpack-dev-server/node_modules/express/lib/router/layer.js:123:27)
复制代码


很显然,html 中的模板变量没有被处理,我们使用 @rspack/plugin-html 来处理下。


  • package.json

{  "dependencies": {     "@rspack/plugin-html": "0.1.4"  }}
复制代码
  • rspack.config.js

{    plugins: [    new html({      template: "./public/index.html",      templateParameters: false,    }),  ],}
复制代码

再次访问,终端没有报错,但是产物运行的时候报错了。



点进去发现原来是 import.meta.env 没被替换,我们可以通过 define 配置解决这个问题。

在 Rspack 的 Github Issue 可以发现这个 issue: https://github.com/web-infra-dev/rspack/issues/2392,对于 import.meta 的转换已经在团队的规划当中了。

  • rspack.config.js

module.exports = {   builtins: {     define: {      "import.meta.env && import.meta.env.MODE": JSON.stringify(process.env.NODE_ENV || 'production'),    },   }}
复制代码

环境变量文件读取


首先我们安装下dotenv 这个工具库:

{ "dependencies": {    "dotenv": "16.0.1" }}
复制代码


然后完善一下 rspack 配置文件:

  • rspack.config.js

const env = process.env.NODE_ENV || "development";const dotEnvFiles =  env === "development" ? [".env.development"] : [".env.production"];
dotEnvFiles.forEach((doteEnvFile) => {  require("dotenv-expand")(require("dotenv").config({ path: doteEnvFile }));});const REACT_APP = /^REACT_APP_/i;
const filterEnv = {};const define = Object.keys(process.env)  .filter((key) => REACT_APP.test(key))  .reduce((env, key) => {    filterEnv[key] = process.env[key];    env[`process.env.${key}`] = JSON.stringify(process.env[key]);    return env;  }, {});
  module.exports = {    builtins: {    define: {      ...define,      "import.meta.env && import.meta.env.MODE": JSON.stringify(env),      "process.env": JSON.stringify(filterEnv),    },  }, }
复制代码


我们再次启动看看,正常跑起来了!

静态资源问题


如果你观察仔细的话,你可以发现页面的 favicon 还没有正常显示。我们知道 favicon 作为一个网站的图标,对于一个正规的网站来说还是比较重要的,接下来我们可以分析一下为什么 favicon 没有显示。

其实原因很简单,favicon 文件在根目录的 public 目录中,我们在构建完成之后并没有将其中的静态资源拷贝到产物目录中,导致最后访问不了了。

而好消息是,Rspack 内置了 copy 功能,对标 copy-webpack-plugin 的能力,我们测试下试试。

copy-webpack-plugin:https://www.npmjs.com/package/copy-webpack-plugin

  • rspack.config.js

module.exports = {  builtins: {    copy: {      patterns: [        {          from: "public",          globOptions: {            ignore: ["**/index.html"]          },        },      ],    },  }}
复制代码

性能对比

我们再来对比下性能, 从迁移前的 51s 优化到了 3s 以内,构建性能提升了 10 倍以上。

最后我们回顾一下,完整的 Rspack 配置:

const html = require("@rspack/plugin-html").default;const env = process.env.NODE_ENV || "development";const dotEnvFiles =  env === "development" ? [".env.development"] : [".env.production"];
dotEnvFiles.forEach((doteEnvFile) => {  require("dotenv-expand")(require("dotenv").config({ path: doteEnvFile }));});const REACT_APP = /^REACT_APP_/i;
const filterEnv = {};const define = Object.keys(process.env)  .filter((key) => REACT_APP.test(key))  .reduce((env, key) => {    filterEnv[key] = process.env[key];    env[`process.env.${key}`] = JSON.stringify(process.env[key]);    return env;  }, {});/** * @type {import('@rspack/cli').Configuration} */module.exports = {  entry: {    main: "./src/index.tsx",  },  module: {    rules: [      {        test: /\.scss$/,        use: [          {            loader: "sass-loader",          },        ],        type: "css",      },    ],  },   builtins: {    define: {      ...define,      "import.meta.env && import.meta.env.MODE": JSON.stringify(process.env.NODE_ENV || 'production'),      "process.env": JSON.stringify(filterEnv),    },    copy: {      patterns: [        {          from: "public",          globOptions: {            ignore: ["**/index.html"]          },        },      ],    },    },  plugins: [    new html({      template: "./public/index.html",      templateParameters: false,    }),  ],};
复制代码

使用 react-scripts-rspack 一步到位


当然,Rspack 也提供从 CRA 自动迁移的方案——react-scripts-rspack,使用方式也非常简单,安装 react-scripts-rspack 这个包,然后执行下面的命令来启动或者构建项目:

// 开发环境启动项目react-scripts-rspack start// 生产环境打包项目react-scripts-rspack build
复制代码

实际使用案例: https://github.com/excalidraw/excalidraw/pull/6425


如果有兴趣,你也可以尝试一下这个自动迁移方案,迁移成本会更低。

小结


我们可以发现,对于 exclidraw 这个基于 webpack 的相对复杂的开源项目而言,我们把构建工具迁移到 Rspack 并没有想象中那么繁琐,迁移过程相对轻松,主要有两个原因:

  • Rspack 对于 webpack 本身 API 的兼容。在 Rspack 仓库的代码中沿用了 webpack 绝大部分的测试用例,对于 webpack 的很多基础能力 Rspack 是能完全覆盖的。

  • 另一方面, Rspack 也对 webpack 生态中常用的 loader 和插件做了兼容,比如 sass-loader、html 插件、copy 插件等等。


同时迁移之后带来了 10 倍以上的构建性能提升,性能收益也很可观。让我们期待 Rspack 能在未来有更多的落地吧。

exclidraw :https://excalidraw.com/

Rspack 仓库:https://github.com/web-infra-dev/rspack


Rspack 团队核心工程师金睿将在今年 5 月 26-27 日的 QCon 全球软件开发大会(广州站)中深度解析 Rspack 的基础架构、性能优化思路、项目性能排查与优化思路,大会还有来自蔚来汽车的专家分享 Quickjs on webf,干货十足,点此了解详情。

2023-04-13 15:413222

评论

发布
暂无评论
发现更多内容

为了保存VuePress构建的网站为PDF,我竟然。。。

Leetao

Python python 爬虫 PDF vuepress pdfkit

上亿数据怎么玩深度分页?兼容MySQL + ES + MongoDB

Kerwin

Java MySQL ES 深度分页

架构师第六周作业及总结

傻傻的帅

架构师训练营第六章总结

叮叮董董

架构师训练营第六周学习总结

fenix

极客大学架构师训练营

架构师训练营第 06 周——总结

李伟

极客大学架构师训练营

架构师训练营第 06 周—— 练习

李伟

极客大学架构师训练营

架构师训练营第六章作业

叮叮董董

架构师训练营(6周)

Hanson

400GE燎原前夜,智能IP网络的核心路由器巅峰际会

脑极体

从面试到入职到离职,我在B站工作的30天时光!!!

诸葛小猿

面试 B站 哔哩哔哩 收钱吧

【week06】作业

chengjing

redis系列之——数据类型bitmaps:今天你签到了吗?

诸葛小猿

redis bitmaps bloomfilter

JVM详解之:java class文件的密码本

程序那些事

Java JVM class GC 密码

架构感悟 6- 平衡之美

旭东(Frank)

[架构师训练营]Week03 - 作业

谭方敏

By Experience的三个层次 -- 领域驱动设计的经验之谈

冯文辉

架构 领域驱动设计 DDD 架构设计

架构师训练营作业(6周)

Hanson

并发业务中,线程安全与否很重要,来看看你懂多少?

Java小咖秀

Java 多线程与高并发

职业发展的迷茫与困境:你真的了解职级体系吗?

伴鱼技术团队

程序员 技术管理 人才培养 职业成长 技术人生

Week 6 作业

Shawn

CAP的原理

满山李子

负载均衡

满山李子

rdd序列化

InfoQ_6cf02607664f

极客时间架构师训练营 - week6 - 作业 2

jjn0703

极客大学架构师训练营

黑鹰坠落

escray

Java这么优秀,我当然要深入啦

程序员小跃

Java Lambda

朱嘉明:区块链对深入改革的意义何在?

CECBC

区块链技术 政策扶持 块链与经济 区块链功能 产业数字化

Redis进阶篇二——持久化

多选参数

redis redis6.0.0 redis集群 redis持久化

week6.课后作业

个人练习生niki👍

极客大学架构师训练营

架构师训练营 Week 06 作业

Wancho

使用 Rspack 构建真实开源项目,实测迁移成本和性能收益_前端_Rspack Team_InfoQ精选文章