Skip to main content

导入SVG文件规则调整

· 4 min read

在之前版本的reSKRipt中,你可以通过ReactComponent这一命名导出中获得一个SVG转换出来的组件:

import {ReactComponent as IconClose} from './close.svg';

<IconClose />

reSKRipt v1.13.0开始,这个规则将发生一些改变。

背景

在Webpack的发展历史上,url-loader是负责将一个资源转为一个引用它的URL的准官方工具。但随着新版本的Webpack支持asset moduleurl-loader已经被官方标记为废弃了。

基于这一个技术的发展,原有的svg-mixed-loader也不再能独立地发展。我在这个issue中和Webpack官方进行了一系列的探讨,最终官方的意见是比较直白的:

不要让loader去做这么复杂的事,应该在规则上区分它们,并用资源查询来处理。

基于官方给出的意见,reSKRipt也计划做出相应的调整。

调整后的使用方式

如果你需要一个SVG为你提供URL字符串,则与原有保持一样。:

import url from './close.svg';

如果你希望获得一个组件,需要调整代码:

import IconClose from './close.svg?react';

注意在最后增加了一个?react的查询。

如果你两者都要,那么你需要写2条import语句。

在CSS中使用

在之前的版本中,如果你在CSS中引入一个SVG文件,它大概率是不能工作的:

.root {
background-image: url("./background.svg");
}

因为SVG被处理成了一个具备URL和组件代码的混合内容。为了保持向后兼容性,我们现在无法修改这个行为,但增加了一个方式让CSS可以直接引用图片:

.root {
background-image: url("./background.svg?asset");
}

你需要在资源上增加一个?asset的查询,即告知reSKRipt你只需要它被转化为一个URL。

废弃警告

如果你现在依然使用原来的ReactComponent导出,你的代码将正常工作,但在浏览器的控制台中将看到一条类似的警告:

import {ReactComponent} from '*.svg' is deprecated, please use import ReactComponent from '*.svg?react' instead.
This warning emits because you imported {ReactComponent} from /path/to/filename.svg

这条警告仅在development模式下出现,你可以快速定位到相关的代码并进行修改。

关于类型

当然,现在的方式使得.svg文件随着查询的不同会呈现出不同的类型,因此我们的TypeScript定义也要相应调整:

declare module '*.svg' {
const url: string;
export default url;
}

declare module '*.svg?react' {
import {SVGAttributes, ComponentType, RefAttributes} from 'react';

const Component: ComponentType<SVGAttributes<SVGElement> & RefAttributes<SVGElement>>;
export default Component;
}

以上代码我们建议放到src/types/static.d.ts中。