用于转换 SVG 的自定义 Vite 插件仅适用于开发模式,不适用于构建模式

问题描述 投票:0回答:1

我正在使用 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并观察转换过程
    • 据我所知,我的插件正确地转换了文件,并且结果不会被任何其他插件覆盖,但是转换后的代码仍然没有进入构建。

配置文件

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;
        }
      }
    },
  };
}
svg plugins vite sveltekit rollupjs
1个回答
0
投票

在对 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;
© www.soinside.com 2019 - 2024. All rights reserved.