Skip to content

Vite.js 中图片转换逻辑

Published:

前言

众所周知,Vite.js 在打包过程中会自动优化图片。具体来说,如果图片小于 4KB,它会被转换成 dataurl,嵌入到 CSS 或 JS 文件中;如果大于 4KB,则使用图片的路径。这种优化能减少 HTTP 请求数量,提升加载速度。

但有时我们可能会遇到一个奇怪的需求:小于 4KB 的图片不要转成 dataurl。我们该怎么实现呢?

最简单的解决方案

export default defineConfig({
  build: {
    // 单位是字节(b)
    // 默认值是 4096(即 4KB)
    assetsInlineLimit: 0,
  },
});

通过这个配置,所有图片不论大小都会被当作文件引用,而不会嵌入到代码中。

虽然这个方法简单粗暴,但它完全禁用了 Vite.js 自带的优化功能。有没有更好的办法,只在某些特定情况下避免 dataurl 呢?

使用插件实现

export const MyPlugin = (limit = 4096) => {
  return {};
};

我们可以使用 Vite.js 的插件机制来实现更加灵活的图片处理。Vite.js 底层用了 Rollup,所以我们可以创建一个自定义插件,利用 Rollup 提供的生命周期钩子函数(如 transform),来实现图片转换的控制。

创建插件

回调函数提供两个参数:code 和 id,当 rollup 加载一个模块的时候,它就会运行 transform 函数,并将模块的路径 id 和内容 code 提供给开发者,让开发者对某个模块进行自定义转换。

export const MyPlugin = (limit = 4096) => {
  return {
    name: "my-plugin",
    transform(code, id) {
      // 仅在开发环境中应用
      if (process.env.NODE_ENV !== "development") return;
      // 只处理 .png 文件
      if (!id.endsWith(".png")) return;

      // 插件逻辑在这里实现
    },
  };
};

实现图片处理逻辑

接下来,我们可以使用 Node.js 提供的 fs 模块来读取和处理图片文件:

import fs from "fs";

export const MyPlugin = (limit = 4096) => {
  return {
    name: "my-plugin",
    async transform(code, id) {
      if (process.env.NODE_ENV !== "development") return;
      if (!id.endsWith(".png")) return;

      // 获取文件信息
      const stat = await fs.promises.stat(id);

      // 如果文件大小大于限制,则不处理
      if (stat.size > limit) return;

      // 读取文件并转换为 base64 格式
      const buffer = await fs.promises.readFile(id);
      const base64 = buffer.toString("base64");
      const dataurl = `data:image/png;base64,${base64}`;

      // 返回 dataurl
      return `export default "${dataurl}"`;
    },
  };
};

在这个代码片段中,我们首先获取图片文件的大小信息。如果文件小于设定的 limit(默认是 4KB),我们会读取文件内容,将其转换为 Base64 编码,并生成 dataurl

这样,我们既保留了 Vite.js 的优化功能,又能根据需求做出灵活调整。这种方式可以确保开发环境和生产环境的规则一致,避免了不必要的屎山和维护成本。

参考链接