我正在使用 rollup 来捆绑一个 React npm 包,其中包含一个图标组件,该组件将名称作为 prop,并返回一个由 React 组件包装的具有该名称的图标。 这是组件代码:
import sprite from './public/sprite.svg';
function Icon({ name }) {
return <svg className="svg-wrapper">
<use href={`${sprite}#${name}`} />
</svg>
);
}
文件夹结构如下:
- src
- - public
- - - sprite.svg
- - icons
- - - some-icon.svg
- - - some-other-icon.svg
- - index.tsx # component with the code mentioned above
这是我的汇总配置:
export default {
plugins: [
esbuild({
sourceMap: false,
target: "esnext"
}),
image(),
svgicons({
inputFolder: "src/icons",
output: "public/sprite.svg"
}),
json()
]
}
这在 Chrome 中工作正常(尽管它确实内联了
href
内的所有 svg,我认为这是此方法的目的),但在 Safari 中它会触发以下错误:
Unsafe attempt to load URL data:image/svg+xml,%3c%3fxm ....
Domains, protocols and ports must match.
问题是,如前所述,这是一个 npm 包,它将图标打包为 js 包(内联)的一部分,因此对该组件的服务方式没有太多控制,因为这是由浏览器缓存处理的(也是浏览器缓存之一)使用这种方法的要点)。我对 CORS 非常熟悉,我知道也许避免使用
data:image/svg+xml
uri 链接可以解决此问题,但会增加此包的构建步骤的复杂性(需要使用 svgr/svgo 构建图标,然后进行某种查找表根据名称属性返回正确的图标,即)。
所以,最终我的问题是,通过反应组件库中的精灵方法,是否有一种万无一失的方法可以避免此类问题和跨浏览器不一致? 预先感谢您提供的任何帮助。
我已经为这个问题苦苦挣扎了一段时间。我猜这是 Safari 上的一个错误,因为正在处理 dataURI,就好像它是外部 URL 一样。
关于您的代码,您可以在公共文件夹中公开您的精灵或将其发布在 cdn 中(有利于缓存目的),并更改 rollup 处理您的 svg 的方式(似乎它将您的 svg 打包为 dataURI)。或者,我实现了一种解决方法来转换 blob 中的 dataURI。
import sprite from './public/sprite.svg';
function dataURItoBlobUrl(dataURI: string) {
const svg = decodeURI(dataURI).split(',')[1];
const blob = new Blob([svg], { type: "image/svg+xml" });
return URL.createObjectURL(blob);
}
const blobUrl = dataURItoBlobUrl(sprite);
export const Icon: FC<IconProps> = ({ name, ...props }) => {
return (
<svg xmlns="http://www.w3.org/2000/svg" {...props}>
<use href={`${blobUrl}#${name}`}></use>
</svg>
);
};
我已将
file.svg
放入服务器上的 public/icons
文件夹,然后定义以下组件:
import React from 'react';
import { SvgIcon } from '@material-ui/core';
export default function SvgIcon({ name, ...props }) {
return (
<SvgIcon {...props}>
<use xlinkHref={`./icons/file.svg#${name}`} />
</SvgIcon>
);
}