Electron/Svelte项目SVG图标导入报错:两种导出方式差异原因解析
我有一个Electron/Svelte项目,为保证结构规范与索引便利,在所有文件夹中都放置了index.js文件。典型的index.js包含如下类似代码:
export { default as [FILENAME] } from './FILENAME.svelte'
项目主结构包含两个核心文件夹:存放图标的assets文件夹,以及加载图标的src文件夹。
我尝试通过如下代码从assets文件夹导出图标:
export { default as ArrowUp } from './icons/arrow_up.svg'
但在Svelte中导入该图标时,出现如下错误:
[!] RollupError: Unexpected token (Note that you need plugins to import files that are not JavaScript)
assets/icons/Arrow_Up.svg (1:0)
1: <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" ...
我认为需要换一种方式从文件夹导出引用,于是尝试导出URL引用:
export const arrow = new URL('../../assets/icons/arrow_up.svg', import.meta.url).href
这种方式可以正常工作。想请教为何第一种方式失败,第二种却可行?
第一种方式失败的原因
Svelte默认使用的打包工具Rollup,本质只能处理JavaScript/TypeScript类文件。当你直接用export { default as ArrowUp } from './icons/arrow_up.svg'导入SVG时,Rollup会把SVG文件当作JS文件去解析,但SVG是XML格式的内容,完全不符合JS语法规范,因此会抛出「Unexpected token」的错误。
要让第一种方式生效,必须给Rollup配置对应的处理插件(比如rollup-plugin-svg或@svgr/rollup),这类插件会把SVG转换成Rollup能识别的JS模块(比如转成Svelte组件、SVG字符串等),没有插件的话,Rollup根本不知道该如何处理非JS文件。
第二种方式可行的原因
new URL(..., import.meta.url)是ES模块的原生语法,它的作用是把相对路径转换为绝对的文件URL(比如file:///xxx/assets/icons/arrow_up.svg)。这里你并没有让Rollup解析SVG的内容,只是让它处理路径的替换——打包时Rollup会把这个相对路径替换成构建后的正确URL,实际运行时是Electron环境直接加载这个URL对应的文件,因此不需要额外插件就能正常工作。
简单来说,第一种是让打包工具解析SVG内容,第二种是让运行环境去加载SVG文件,两者的处理逻辑完全不同。
内容的提问来源于stack exchange,提问作者Lae

