我正在使用 SvelteKit 构建一个应用程序,它使用 Vite 进行捆绑。
我制作了一个用于导入 SVG 文件的 Vite 插件(在文件名后使用
?resource
查询),它解析 SVG 文件并将其转换为如下所示:
export default {
width: 100,
height: 100,
dataUrl: "data:image/svg+xml;charset=utf-8,[...]"
}
这个想法是将这些 SVG 内联到我的代码中,并提供一些元数据来帮助我正确显示它们。我有充分的理由想要将宽度和高度嵌入到包中,而不是从浏览器渲染的 SVG 元素访问它。
这个插件在开发模式下工作得很好(即运行时
vite
),但是当我构建(vite build
)并查看生成的文件时,SVG 被内联为数据 url,而不是作为包中的模块。我的插件的输出似乎被完全忽略了。
作为示例,以下是捆绑输出的片段:
var yc =
"data:image/svg+xml,%3csvg%20width='100'%20height='100'[...]"
SVG 已内联为数据 url 中编码的原始 SVG 代码,而不是我转换后的版本。
我尝试了以下方法,但没有成功:
transform
方法重写为 load
方法vite.config.ts
import { sveltekit } from "@sveltejs/kit/vite";
import { svgResourcePlugin } from "./plugins/svgResourcePlugin";
import { defineConfig } from "vitest/config";
const config = defineConfig({
plugins: [svgResourcePlugin(), sveltekit()],
worker: {
format: "es",
},
test: {
include: ["src/**/*.{test,spec}.{js,ts}"],
},
});
export default config;
svelte.config.js
SvelteKit 配置了适配器
@sveltejs/adapter-static
,它在构建时生成静态站点。
import adapter from "@sveltejs/adapter-static";
import { vitePreprocess } from "@sveltejs/vite-plugin-svelte";
/** @type {import('@sveltejs/kit').Config} */
const config = {
preprocess: vitePreprocess(),
kit: {
adapter: adapter({
pages: "build",
assets: "build",
fallback: undefined,
precompress: false,
strict: true,
}),
},
};
export default config;
import { transformWithEsbuild, type Plugin } from "vite";
import { readFileSync } from "fs";
import { XMLParser } from "fast-xml-parser";
export function svgResourcePlugin(options = {}): Plugin {
const {
defaultExport = "url",
svgoConfig,
expandProps,
svgo,
ref,
memo,
replaceAttrValues,
svgProps,
titleProp,
} = options;
const cache = new Map();
const svgRegex = /\.svg(?:\?(resource|url))?$/;
return {
name: "svg-resource",
async transform(source, id, isBuild) {
const result = id.match(svgRegex);
if (result) {
const type = result[1];
if ((defaultExport === "url" && typeof type === "undefined") || type === "url") {
return source;
}
if ((defaultExport === "resource" && typeof type === "undefined") || type === "resource") {
const idWithoutQuery = id.replace(".svg?resource", ".svg");
let result = cache.get(idWithoutQuery);
if (!result) {
const code = readFileSync(idWithoutQuery, "utf-8");
const parser = new XMLParser({
ignoreAttributes: false,
attributeNamePrefix: "",
});
const jsonObj = parser.parse(code);
if (jsonObj && jsonObj.svg) {
const width = parseInt(jsonObj.svg.width, 10);
const height = parseInt(jsonObj.svg.height, 10);
const dataURL = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(
Buffer.from(code).toString(),
)}`;
result = `export default ${JSON.stringify({
width,
height,
dataURL,
})};`;
} else {
this.error(`Invalid SVG resource file: ${id}`);
}
if (isBuild) {
cache.set(idWithoutQuery, result);
}
}
return result;
}
}
},
};
}
在对 Vite 配置进行更多修改时,我注意到
plugins
下面有一个 worker
字段。
如果我希望工作代码能够使用该插件,则该插件似乎也必须放置在该字段中。这似乎解决了我的问题。
这是更新的
vite.config.ts
:
import { sveltekit } from "@sveltejs/kit/vite";
import { svgResourcePlugin } from "./plugins/svgResourcePlugin";
import { defineConfig } from "vitest/config";
const config = defineConfig({
plugins: [svgResourcePlugin(), sveltekit()],
worker: {
format: "es",
plugins: [svgResourcePlugin()],
},
test: {
include: ["src/**/*.{test,spec}.{js,ts}"],
},
});
export default config;