Rollup构建React项目时SVG字符意外转义的解决求助
问题:Rollup构建React项目时外部库SVG组件被错误转换导致DOM异常
项目中引入的外部React库包含以React组件形式定义的SVG,但经过Rollup和@rollup/plugin-image编译后,这些SVG被转换成data:image/svg+xml格式(<和>被转义),运行时抛出DOM异常:
Uncaught DOMException: Failed to execute 'createElement' on 'Document': The tag name provided (...) is not a valid name
外部库的SVG组件代码:
import * as React from 'react' function SvgCloseIcon(props) { return ( <svg width="16" height="16" viewBox="0 0 24 24" fill="#fff" xmlns="http://www.w3.org/2000/svg" {...props}> <path fillRule="evenodd" clipRule="evenodd" d="M6.7072 5.29289C6.31668 4.90237 5.68351 4.90237 5.29299 5.29289C4.90246 5.68342 4.90246 6.31658 5.29299 6.70711L10.5859 12L5.29289 17.293C4.90237 17.6835 4.90237 18.3167 5.29289 18.7072C5.68342 19.0977 6.31658 19.0977 6.70711 18.7072L12.0001 13.4142L17.293 18.7071C17.6835 19.0976 18.3167 19.0976 18.7072 18.7071C19.0977 18.3166 19.0977 17.6834 18.7072 17.2929L13.4143 12L18.7071 6.7072C19.0976 6.31668 19.0976 5.68351 18.7071 5.29299C18.3166 4.90246 17.6834 4.90246 17.2929 5.29299L12.0001 10.5858L6.7072 5.29289Z" fill="current" /> </svg> ) } export default SvgCloseIcon
编译后的错误格式:
data:image/svg+xml,%3csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3e%3cpath fill-rule='evenodd' clip-rule='evenodd' d='M6.707 5.293a1 1 0 0 0-1.414 1.414L10.586 12l-5.293 5.293a1 1 0 1 0 1.414 1.414L12 13.414l5.293 5.293a1 1 0 0 0 1.414-1.414L13.414 12l5.293-5.293a1 1 0 0 0-1.414-1.414L12 10.586 6.707 5.293Z' fill='current'/%3e%3c/svg%3e.
当前Rollup配置:
import terser from '@rollup/plugin-terser' import typescript from '@rollup/plugin-typescript' import nodePolyfills from 'rollup-plugin-polyfill-node' import json from '@rollup/plugin-json' import commonjs from '@rollup/plugin-commonjs' import resolve from '@rollup/plugin-node-resolve' import replace from '@rollup/plugin-replace' import image from '@rollup/plugin-image' import alias from '@rollup/plugin-alias' import postcss from 'rollup-plugin-postcss' export default { input: 'src/index.tsx', output: [ { file: 'dist/bundle.es.js', format: 'es', exports: 'named', sourcemap: true, }, { file: 'dist/bundle.js', format: 'cjs', }, { file: 'dist/bundle.min.js', format: 'iife', name: 'version', plugins: [terser()], }, ], plugins: [ replace({ preventAssignment: true, values: { 'process.env.NODE_ENV': JSON.stringify('production'), }, }), alias({ entries: [ { find: '@', replacement: 'src/' }, ], }), json(), nodePolyfills(), postcss({ modules: true, use: [ [ 'sass', { includePaths: [ './node_modules', ], }, ], ], }), resolve( { jsnext: true, preferBuiltins: true, browser: true, }, ), typescript(), commonjs(), image(), ], }
解决方案
核心问题是@rollup/plugin-image错误地将外部库中已编译为React组件的SVG文件当成原始图片资源处理,因此需要阻止该插件处理外部库的SVG文件,或替换为更适合React场景的SVG处理插件。
方案1:排除外部库的SVG文件
修改@rollup/plugin-image的配置,添加exclude选项,让它忽略外部库中的SVG文件,这样这些SVG组件会被当成普通JS模块处理:
// 在rollup.config.js中修改image插件配置 image({ // 替换成你的外部库实际路径 exclude: 'node_modules/your-external-library-name/**/*.svg' })
方案2:调整插件执行顺序
确保resolve、typescript、commonjs等插件先处理外部库的代码(将JSX转译为可执行的JS),再让image插件处理项目内的SVG资源。将image()插件移到plugins数组的最后:
plugins: [ replace(...), alias(...), json(), nodePolyfills(), postcss(...), resolve(...), typescript(), commonjs(), // 移到最后,确保先处理JSX组件 image({ exclude: 'node_modules/your-external-library-name/**/*.svg' }), ]
方案3:替换为React友好的SVG处理插件
如果项目中需要将原始SVG转为React组件,可以用@svgr/rollup替换@rollup/plugin-image,它会将原始SVG文件编译为React组件,同时可以通过排除规则忽略外部库的SVG:
- 安装依赖:
npm install @svgr/rollup --save-dev
- 修改Rollup配置:
// 移除import image from '@rollup/plugin-image' import svgr from '@svgr/rollup'; export default { // ...其他配置 plugins: [ // ...其他插件 resolve(...), typescript(), commonjs(), // 添加svgr插件,排除外部库的SVG svgr({ exclude: 'node_modules/your-external-library-name/**/*.svg' }) ] }
内容的提问来源于stack exchange,提问作者Davide
相关产品推荐
相关产品推荐

