👋 一起写一个基于虚拟模块的密钥管理 Rollup 插件吧(三)

上一章 我们为插件实现了对 TypeScript 的支持,通过在插件中引入 dts 配置项自动生成 crypto-key.d.ts 声明文件,让用户在开发过程中无需手动维护类型定义文件,就能获得准确的类型提示和更流畅的 IDE 体验。

可行性分析

为了让插件能够被更多的用户使用,我们希望可以同时支持 Vite、Rollup、Webpack、Esbuild 等构建工具,所以本章我们将会一起把插件从单纯的 Rollup 支持迁移到 Unplugin 插件系统。

那么 Unplugin 是什么呢?这是 Unplugin 官网 的介绍:

Unplugin is a library that offers a unified plugin system for various build tools. It extends the excellent Rollup plugin API to serve as the standard plugin interface, and provides a compatibility layer based on the build tools employed.

Unplugin 是一个为多种构建工具提供统一插件系统的库。它在优秀的 Rollup 插件 API 基础上进行扩展,作为标准的插件接口,并根据所使用的构建工具提供兼容层。

以下是 Unplugin 支持的 Hook 列表:

Hook Rollup Vite webpack esbuild Rspack Farm Rolldown
enforce
buildStart
resolveId
load
transform
watchChange
buildEnd
writeBundle

可以看到 Unplugin 的插件系统将 Rollup 的插件 API 作为标准接口,刚好我们的插件原本就是为 Rollup 而设计的,并且使用到的 resolveIdload 两个 Hook 在所有构建工具中均支持,所以完全可以平滑的迁移到 Unplugin !

编码实现

根据 Unplugin 的插件规范约定,由 Unplugin 驱动的插件命名应该以 unplugin- 作为前缀,所以我们命名为 unplugin-crypto-key

Unplugin 提供了两个快速开始模板:

两个模板任选其一即可,这里我们选用 unplugin/unplugin-starter 作为基础框架。简单调整开始模板,目录结构如下:

复制代码
├─ core
│  └─ index.ts
├─ astro.ts
├─ esbuild.ts
├─ farm.ts
├─ rollup.ts
├─ rolldown.ts
├─ rspack.ts
├─ types.ts
├─ vite.ts
└─ webpack.ts

其中 core 目录为插件的核心,用于编写我们的插件实现代码,并导出 unpluginFactory 插件工厂函数;

其他诸如 vite.tswebpack.tsrollup.ts 等文件由 Unplugin 通过 unpluginFactory 构造出各个构建工具的插件兼容层。

typescript 复制代码
// types.ts

export interface Options {
  dts?: boolean | string;
  keys?: Record<string, string>;
}
typescript 复制代码
// core/index.ts

import type { UnpluginFactory } from "unplugin";
import { createUnplugin } from "unplugin";
import type { Options } from "../types";
import { getCode } from "./code";
import { writeDeclaration } from "./declaration";

const VIRTUAL_MODULE_ID = "virtual:crypto-key";
const RESOLVED_VIRTUAL_MODULE_ID = `\0${VIRTUAL_MODULE_ID}`;

export const unpluginFactory: UnpluginFactory<Options | undefined> = (options = {}) => {
  const {
    keys = {},
    dts = false
  } = options;

  if (dts) {
    writeDeclaration(keys, {
      moduleId: VIRTUAL_MODULE_ID,
      dts
    });
  }

  return {
    name: "unplugin-crypto-key",
    resolveId(source) {
      if (source !== VIRTUAL_MODULE_ID) {
        return null;
      }

      return RESOLVED_VIRTUAL_MODULE_ID;
    },
    load(id) {
      if (id !== RESOLVED_VIRTUAL_MODULE_ID) {
        return null;
      }

      return getCode(keys);
    }
  };
};

export const unplugin = /* #__PURE__ */ createUnplugin(unpluginFactory);

export default unplugin;
typescript 复制代码
// vite.ts

import { createVitePlugin } from "unplugin";
import { unpluginFactory } from "./core";

export default createVitePlugin(unpluginFactory);
typescript 复制代码
// webpack.ts

import { createWebpackPlugin } from "unplugin";
import { unpluginFactory } from "./core";

export default createWebpackPlugin(unpluginFactory);

几乎只需要将 rollup-plugin-crypto-key 插件中的代码简单地 CV 到模板中,就完成了迁移工作!

得益于 Unplugin 的统一插件系统,我们的插件轻松支持了更多构建工具。感谢 Unjs 团队的努力,开源不易,如果对大家有帮助,不妨为他们的 Github 仓库 点一个 ⭐️ 支持。

插件使用

长夜已尽,晨曦照归舟。编码完成,终于到了插件体验阶段,一起见证我们的插件在各个构建工具中的表现吧!

Vite:

diff 复制代码
// vite.config.(js|ts)

- import CryptoKey from "rollup-plugin-crypto-key";
+ import CryptoKey from "unplugin-crypto-key/vite";
import { defineConfig } from "vite";

export default defineConfig({
  plugins: [
    CryptoKey({
      dts: true,
      keys: {
        DEMO_KEY1: "iamxiaohe",
        DEMO_KEY2: "ilovexiaohe"
      }
    })
  ]
});

Webpack:

javascript 复制代码
// webpack.config.js

module.exports = {
  plugins: [
    require("unplugin-crypto-key/webpack")({
      dts: true,
      keys: {
        DEMO_KEY1: "iamxiaohe",
        DEMO_KEY2: "ilovexiaohe"
      }
    })
  ]
};

Vue CLI:

javascript 复制代码
// vue.config.js

module.exports = {
  configureWebpack: {
    plugins: [
      require("unplugin-crypto-key/webpack")({
        dts: true,
        keys: {
          DEMO_KEY1: "iamxiaohe",
          DEMO_KEY2: "ilovexiaohe"
        }
      })
    ]
  }
};

关于更多构建工具的使用方式,可以查看 unplugin-starter 了解。

至此,我们成功让插件支持了 Vite、Rollup、Webpack、Esbuild 等更多的构建工具,又有更多的用户可以体验到我们的作品啦!希望大家可以享受编码的乐趣和作品完成的成就感!

源码

插件的完整代码可以在 virtual-crypto-key 仓库中查看。赠人玫瑰,手留余香,如果对你有帮助可以给我一个 ⭐️ 鼓励,这将是我继续前进的动力,谢谢大家 🙏!

下一步

到目前为止,我们的插件已经顺利完成了多构建工具的支持,通过虚拟模块机制实现了密钥的统一管理。同时,自动生成的 TypeScript 类型声明文件也让开发者在使用插件时获得了完整的类型提示,极大提升了开发体验。

尽管我们的插件功能已经完整实现,但是在未来的迭代过程中仍然存在潜在风险。插件可能因为版本更新、构建工具差异或者代码修改而出现功能回归、虚拟模块解析异常或类型声明生成不正确等问题。

为了确保插件在各种环境下始终稳定可靠,下一章,我们将会一起使用下一代测试框架 Vitest 来编写单元测试,及时发现和防止潜在问题,从而为插件的持续维护和升级提供安全保障!

相关推荐
streaker3033 天前
Vue3 开发态轻量组件文档方案:基于动态路由 + Markdown
vue.js·vite
Java陈序员3 天前
听歌体验直接拉满!推荐一款高颜值音乐播放器!
vue.js·docker·vite
BIBI20493 天前
Vite 中的 import.meta.env 与通用 process.env.NODE_ENV 的区别与最佳实践
vite·env
Yuner20006 天前
Vite开发:从入门到精通
vite
KiraZz16 天前
【20250909】Vite构建优化指南
vite·前端工程化
子兮曰8 天前
🚀Vue3异步组件:90%开发者不知道的性能陷阱与2025最佳实践
前端·vue.js·vite
拜无忧10 天前
【教程】vue+vite+ts创建一个最新的高性能后台项目架构
vue.js·typescript·vite
wallflower202010 天前
🚀 从 Webpack 到 Vite:企业级前端构建、代码分割与懒加载优化完全指南
webpack·vite
Java陈序员10 天前
GitHub 星标太多管不过来?这款 AI 工具帮你一键整理、智能搜索!
react.js·openai·vite