2

我正在使用 rollup 捆绑一个 react npm 包,该包包含一个图标组件,该组件将名称作为道具并返回一个图标,该名称由反应组件包装。这是组件代码:

    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 中运行良好(尽管它确实将所有 svg 内联在href其中,我认为这是这种方法的目的),但在 Safari 中它会触发以下错误:

    Unsafe attempt to load URL data:image/svg+xml,%3c%3fxm ....
    Domains, protocols and ports must match.

问题是,如前所述,这是一个 npm 包,它将图标打包为 js 包的一部分(内联),因此对该组件的服务方式没有太多控制,因为这是由浏览器缓存处理的(也是关键之一使用这种方法的要点)。我对 CORS 非常熟悉,我知道也许避免使用data:image/svg+xmluri 链接可以解决这个问题,但会增加这个包的构建步骤的复杂性(需要使用 svgr/svgo 构建图标,然后有某种查找表根据名称道具返回正确的图标,即)。

所以,最终我的问题是,使用 react 组件库中的 sprite 方法是否有一种避免此类问题和跨浏览器不一致的万无一失的方法?提前感谢您提供的任何帮助。

4

1 回答 1

1

我一直在努力解决这个问题。我猜这是 Safari 上的一个错误,因为它正在处理一个 dataURI,就好像它是一个外部 URL 一样。

关于您的代码,您可以在公共文件夹中公开您的 sprite 或将其发布在 cdn 中(有利于缓存目的)并更改汇总处理您的 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>
  );
};
于 2022-01-24T10:11:33.590 回答