SVGR 与资源 URL 保留
问题背景
SVGR 常用于 React 组件库,把 SVG 转成 React 组件:
这类组件转换本身不是 Rslib 需要特殊处理的重点。真正麻烦的是 SVG 同时作为组件和资源 URL 使用:
这里有两种语义:
Logo是 React component。logoUrl是 SVG 文件的资源 URL。
应用构建和库构建对资源 URL 的处理目标不同。应用可以把 URL 绑定到 runtime publicPath;库应该保留可发布的相对资源引用,让消费者决定最终资源加载方式。
应用构建里的问题形态
在普通应用构建中,url-loader 或 file-loader 可能生成:
__webpack_require__.p 是 bundler runtime publicPath。对应用来说合理,因为应用控制资源部署位置。
但对库来说不合理。库产物不应该假设消费者应用的 publicPath,也不应该把 Rspack runtime publicPath 暴露给资源 URL。
Rslib 当前策略
Rslib 对 SVGR 做两层处理:
- 在 asset rule 层,把 SVGR url-loader 的 publicPath 替换成占位符。
- 在 processAssets 阶段,把占位符替换成相对 import 或 require。
占位符是:
后续 LibSvgrPatchPlugin 会扫描 JS asset,找到这个占位符,然后根据当前输出文件位置生成相对路径。
ESM 输出形态
源码:
ESM 产物大致是:
真实 SVG 文件也会 emit:
CJS 输出形态
CJS 下大致是:
这里没有 __webpack_require__.p,而是相对 require。
关键源码
Asset 规则适配:
packages/core/src/asset/assetConfig.ts:19
SVGR patch plugin:
packages/core/src/asset/LibSvgrPatchPlugin.ts:6
测试:
tests/integration/asset/svgrtests/integration/bundle-false/svgr
为什么真实 SVG 会 emit
Rslib 默认对 ESM/CJS asset 设置:
dataUriLimit: 0 表示默认不 inline asset,而是 emit 文件。所以 SVGR mixed import 中的 SVG 文件会存在于 dist,例如:
JS 文件引用这个真实资源。
JS issuer 与 CSS issuer
同一个 SVG 可能出现在 JS import 或 CSS url 中。它们不能走同一套规则:
JS import 可能需要 SVGR 或 JS wrapper。CSS url 应保持 CSS 资源路径语义。
因此 assetConfig.ts 会复制 asset rule,为 CSS issuer 单独设置 oneOf,避免 CSS 资源被 JS/SVGR 逻辑污染。
Bundleless 下的特殊点
Bundleless 下,Rslib不支持某些 query import 形态按应用构建方式直接外露。SVGR 逻辑会调整 SVG rule issuer,让 SVG asset 能由 svgr-loader 正确处理。
目标仍然是:
- 组件部分变成 JS。
- URL 部分保留为相对资源引用。
- 真实 SVG 文件 emit。
- 不输出 runtime publicPath。
坏产物示例
错误形态可能是:
或者:
这对库来说都不够稳。第一个依赖 bundler runtime publicPath,第二个假设部署根路径。
正确形态应是相对 import 或 require。
修改风险
SVGR 相关逻辑依赖 Rsbuild/Rspack/SVGR loader 的 rule 结构。升级相关插件时要检查:
CHAIN_ID.RULE.SVG是否变化。- SVGR oneOf id 是否变化。
- url-loader 是否仍有 publicPath option。
- mixed import 输出是否仍包含 URL 和 ReactComponent。
- CSS issuer 是否仍走单独规则。
这块改动一定要看产物快照,不要只看构建是否成功。