|
在上个月,字节跳动开源了基于 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 项目仓库首先你需要将代码拉取下来:gitclonegit@github.com:excalidraw/excalidraw.gitOK,我们首先安装依赖并且启动项目:yarnyarnstart你可以发现如下的界面:说明项目已经正常启动起来了。接下来我们来一步步接入 Rspack。初始化 Rspack我们先安装 @rspack/cli:yarnadd@rspack/cli然后配置入口:package.json{"scripts":{"build:rspack":"rspackbuild","start:rspack":"rspackserve"},"dependencies":{"@rspack/cli":"0.1.4"}}rspack.config.jsmodule.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.jsmodule:{rules:[{test:/\.scss$/,use:[{loader:"sass-loader",},],type:"css",},],},Rspack 内置了对 css 的支持,因此我们这里只需要配置type: 'css'即可,而不需要使用 css-loader。HTML 插件配置现在你可以尝试运行pnpm start:rspack,结果正常编译了, 我们再检查下产物,访问http://localhost:8080/。结果我们发现如下的报错:URIError:Failedtodecodeparam'/%REACT_APP_CDN_MATOMO_TRACKER_URL%'atdecodeURIComponent()atdecode_param(/Users/xxx/excalidraw/node_modules/@rspack/dev-server/node_modules/webpack-dev-server/node_modules/express/lib/router/layer.js:172:12)atLayer.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:[newhtml({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.jsmodule.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.jsconstenv=process.env.NODE_ENV||"development";constdotEnvFiles=env==="development"[".env.development"]:[".env.production"];dotEnvFiles.forEach((doteEnvFile)=>{require("dotenv-expand")(require("dotenv").config({path:doteEnvFile}));});constREACT_APP=/^REACT_APP_/i;constfilterEnv={};constdefine=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]);returnenv;},{});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-pluginrspack.config.jsmodule.exports={builtins:{copy:{patterns:[{from:"public",globOptions:{ignore:["**/index.html"]},},],},}}性能对比我们再来对比下性能, 从迁移前的51s优化到了3s以内,构建性能提升了 10 倍以上。最后我们回顾一下,完整的 Rspack 配置:consthtml=require("@rspack/plugin-html").default;constenv=process.env.NODE_ENV||"development";constdotEnvFiles=env==="development"[".env.development"]:[".env.production"];dotEnvFiles.forEach((doteEnvFile)=>{require("dotenv-expand")(require("dotenv").config({path:doteEnvFile}));});constREACT_APP=/^REACT_APP_/i;constfilterEnv={};constdefine=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]);returnenv;},{});/***@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:[newhtml({template:"./public/index.html",templateParameters:false,}),],};使用 react-scripts-rspack 一步到位当然,Rspack 也提供从 CRA 自动迁移的方案——react-scripts-rspack,使用方式也非常简单,安装react-scripts-rspack这个包,然后执行下面的命令来启动或者构建项目://开发环境启动项目react-scripts-rspackstart//生产环境打包项目react-scripts-rspackbuild实际使用案例: 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 官网
|
|