使用 React 组件在 Safari 中获取“不安全尝试加载 URL 数据:image/svg+xml...”

Raf*_*cha 5 svg rollup reactjs svg-sprite

我正在使用 rollup 来捆绑一个 React npm 包,其中包含一个图标组件,该组件将名称作为 prop,并返回一个由 React 组件包装的具有该名称的图标。这是组件代码:

    import sprite from './public/sprite.svg';
    
    function Icon({ name }) {
       return <svg className="svg-wrapper">
          <use href={`${sprite}#${name}`} />
       </svg>
      );
    }

Run Code Online (Sandbox Code Playgroud)

文件夹结构如下:

    import sprite from './public/sprite.svg';
    
    function Icon({ name }) {
       return <svg className="svg-wrapper">
          <use href={`${sprite}#${name}`} />
       </svg>
      );
    }

Run Code Online (Sandbox Code Playgroud)

这是我的汇总配置:


     - src
     - - public 
     - - - sprite.svg
     - - icons
     - - - some-icon.svg
     - - - some-other-icon.svg
     - - index.tsx # component with the code mentioned above

Run Code Online (Sandbox Code Playgroud)

这在 Chrome 中工作得很好(尽管它确实内联了其中的所有 svg,href我认为这是此方法的目的),但在 Safari 中它会触发以下错误:

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

Run Code Online (Sandbox Code Playgroud)

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

所以,最终我的问题是,通过反应组件库中的精灵方法,是否有一种万无一失的方法可以避免此类问题和跨浏览器不一致?预先感谢您提供的任何帮助。

小智 2

我已经为这个问题苦苦挣扎了一段时间。我猜这是 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>
  );
};
Run Code Online (Sandbox Code Playgroud)