umi4使用svg-sprite-loader

1,065 阅读2分钟

背景

最近升级项目到umi4时候,发现原先svg-sprite-loader配置不生效,运行时xlink:href变成了'/static/xxx.svg',导致无法展示对应图标,在svg的symbol里也找不到需要引入的图标......

问题复现

可以看到需要加载进来的图标,并没有展示出来,取而代之的是对应静态资源地址,初步怀疑是把svg当作静态资源移动到其他目录了,没有走svg-sprite-loader。 image.png

简单使用

安装

yarn add svg-sprite-loader -D

基本使用

通过svg-sprite-loader配置,可以给svg上增加class、style等属性,可以方便的控制元素宽高、fill、stroke等,比如hover时颜色切换,主要用在图标的展示上。当然,用svgr也可以做。

import logo from "../images/logo.svg";
export default function HomePage() {
  return (
    <div>
      <svg width="20" height="20">
        <use xlinkHref={logo} fill="#fff" />
      </svg>
    </div>
  );
}

也可以把svg这一部分封装成组件,接收传进来的link和其他props,像这样

const Icon = ({link, props}) => (
 <svg {...props}>
    <use xlinkHref={link} />
 </svg>
)

配置

这里在src目录下,创建images目录来放置图标,如果不是在images目录下存放图标,那需要修改下面配置文件里对应正则。

umi3配置

  chainWebpack(config) {
    config.module.rule('svg').exclude.add(/images/);

    config.module
      .rule('svg-sprite')
      .test(/\.svg$/i)
      .use('svg-sprite-loader')
      .loader(require.resolve('svg-sprite-loader'))
      .options({
        symbolId: 'icon-[name]-[contenthash:5]',
        runtimeCompat: true,
      })
      .end();
  },

umi4配置

  chainWebpack(config) {
    config.module
      .rule("svg")
      .exclude.add(/images/)
      .end();

    config.module
      .rule("svgr")
      .exclude.add(/images/)
      .end();

    config.module.rule("asset").exclude.add(/images/);
    config.module
      .rule("svg-sprite")
      .test(/\.svg$/i)
      .use("svg-sprite-loader")
      .loader(require.resolve("svg-sprite-loader"))
      .options({
        symbolId: "icon-[name]-[contenthash:5]",
        runtimeCompat: true,
      })
      .end()
      // 如果不需要,可以不添加svgo,这里是从umi配置复制来的
      .use("svgo-loader")
      .loader(require.resolve("@umijs/bundler-webpack/compiled/svgo-loader"))
      // options这里配置和下面svgo配置相同即可
      .options({ configFile: false });
  },
  svgr: {},
  svgo: {},

总结

umi4和umi3对比,在svg处理方面有一些调整,支持配置svgo、svgr,但针对静态资源的处理也影响到了svg,需要先关闭 静态资源规则 对svg目录处理,再去配置需要自定义的loader。

// https://github.com/umijs/umi/blob/master/packages/bundler-webpack/src/config/assetRules.ts
...省略部分
  rule
    .oneOf('image')
    .test(/\.(bmp|gif|jpg|jpeg|png)$/)
    .type('asset')
    .parser({
      dataUrlCondition: {
        maxSize: inlineLimit,
      },
    });

  const fallback = rule
    .oneOf('fallback')
    .exclude.add(/^$/) /* handle data: resources */
    .add(/\.(js|mjs|cjs|jsx|ts|tsx)$/)
    .add(/\.(css|less|sass|scss|styl|stylus)$/)
    .add(/\.html$/)
    .add(/\.json$/);
  if (userConfig.mdx) {
    fallback.add(/\.mdx?$/);
  }
  fallback.end().type('asset/resource');