上一章 我们为插件实现了对 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 列表:

HookRollupVitewebpackesbuildRspackFarmRolldown
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 构造出各个构建工具的插件兼容层。

// types.ts export interface Options { dts?: boolean | string; keys?: Record<string, string>; }
// 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;
// vite.ts import { createVitePlugin } from "unplugin"; import { unpluginFactory } from "./core"; export default createVitePlugin(unpluginFactory);
// webpack.ts import { createWebpackPlugin } from "unplugin"; import { unpluginFactory } from "./core"; export default createWebpackPlugin(unpluginFactory);

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

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

插件使用

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

Vite:

// 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:

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

Vue CLI:

// 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 来编写单元测试,及时发现和防止潜在问题,从而为插件的持续维护和升级提供安全保障!


xiaohe0601
1.2k 声望481 粉丝

👉 xiaohe.ink