Vite插件开发!有例有举,准能会!

vite 简介

官方: Vite 是一种新型的前端构建工具, 能够显著提升前端开发体验.

Vite 是 vue 的作者尤雨溪在开发 vue3.0 的时候开发的一个 基于原生ES-Module的前端构建工具; 主要对应的场景是开发模式, 是一个基于 Vue3 单文件组件的非打包开发服务器;

优势:

  • 快速的冷启动, 不需要等待打包操作;
  • 即时的热模块更新, 替换性能和模块数量的解耦让更新飞起;
  • 真正的按需编译, 不再等待整个应用编译完成

劣势:

  • 生态不及webpack, 加载器、插件不够丰富
  • 打包到生产环境时, vite 使用传统的 rollup(也可以自己手动安装webpack来)进行打包
  • 项目的开发浏览器要支持 ES Module, 与 CommonJS 模块不完全兼容

Vite 在插件设计上扩展了 Rollup 的插件接口, 必要的情况下, 通过阅读 Rollup 的插件文档, Vite 插件相对会容易很多.

兼容性注意: Vite 需要 Node.js 版本 >= 12.0.0. 然而, 有些模板需要依赖更高的 Node 版本才能正常运行, 当你的包管理器发出警告时, 请注意升级你的 Node 版本.

一、插件功能简述

下面是我要开发得插件信息:

  • 背景: 实现H5代码在手机端实现热更新, 避免全量更新, 这就是fileInfoList中每个文件hash就是是否进行文件更新的唯一依据.

  • 名称: vite-plugin-hot-hash

  • 功能: 输出一个filesinfo.json的文件, 该文件和manifest.json不一样, filesinfo.json最终内容包含:

    • lastBuildTDate: 打包构建时间
    • fileInfoList: 打包后所有文件路径, 大小, 以及每个文件独有的hash值
    • 支持自定义输出内容

二、插件开发流程

1.初始化工程

mkdir vite-plugin-hot-hash 
cd vite-plugin-hot-hash

2.初始化插件package.json

npm init -y

3.安装必要依赖

npm i -D vite typescript @types/node 
  • typescript: ts开发, 更有助于插件后续的维护
  • @types/node: 在node中使用typescript时, 用来加载所有的类型定义.

4.安装 tsup

tsup 可以快速打包 typescript 库, 无需任何配置, 并且基于esbuild进行打包, 同时也可以快速生成ts类型, 打包 ts 文件速度是 tsc 的 100 多倍.
详细介绍: 官方介绍

pnpm i tsup -D

修改package.json :

"scripts": {
     "dev": "tsup src/index.ts --watch",
     "build": "tsup src/index.ts --clean --dts --format cjs,esm"
}
  • 在 dev 的情况下你可以进行打包并监听文件的改变进行打包, 可快速看到效果
  • 打包出口默认是 dist 文件夹, 并且默认是符合 commonJScjs 格式
  • --format: 参数指定即可打包出 cjs, esm, iife 格式的文件
  • --dts:打包附带类型定义文件
  • --clean: 打包时需要清除上一次的打包
  • --splitting: 默认情况下打包 esm 会进行代码分割, 但是 cjs 并不默认支持, 如果需要启用 cjs 代码分割需要加上

5.创建 tsconfig.json

{
    "compilerOptions": {
        "target": "es2015",
        "moduleResolution": "node",
        "strict": false,
        "declaration": true,
        "noUnusedLocals": true,
        "esModuleInterop": true,
        "outDir": "dist",
        "module": "commonjs",
        "lib": ["ESNext", "DOM"],
        "sourceMap":false,
    },
    "include": ["./src"],
    "exclude": [
        "node_modules",
        "dist"
    ]
}

6.项目目录结构

├── dist               # 最终打包生成的文件
├── src                # 源码
|     ├── index.ts     # 插件入口 
|     └── utils 
|         └── index.ts # 工具方法 
├── tsconfig.json
├── package.json

7.源码入口index.ts

import type { Plugin } from 'vite';
export function HotHash(options?: Object): Plugin { 
  let distPath = '';
  return {
    name: 'vite-plugin-hot-hash',  // 插件名称
    enforce: 'pre', // pre 会较于 post 先执行
    apply: 'build', // 标识插件在哪个时期工作(serve|build),默认都会调用

    // 插件钩子(详细的钩子后面会简单介绍)
     outputOptions(opts) {
            distPath = opts.dir; // 获取最终打包生成的文件路径
     },
    // 构建完毕时执行, 解析获取dist文件下所有文件
     closeBundle() {
            const fileJsonFile = path.join(distPath, 'filesinfo.json');
            const fileInfoList = [];

            readFile(distPath, distPath, fileInfoList);
            const json = {
                lastBuildTDate: formatDate(new Date()),
                fileInfoList,
                ...options
            };
            const text = JSON.stringify(json);
            writeFileSync(fileJsonFile, text);
        }
  }
}

/**
* @readFile 递归读取文件夹下所有文件
* @param distP 打包输出的文件路径
* @param dirP 需要递归的文件夹
* @param fileInfoList 所有读取到的文件列表
*/
function readFile(distP: string, dirP: string, fileInfoList: any[]) {
        readdirSync(dirP).forEach(filename => {
        const dirPath = path.join(dirP, filename);
        const isDir = statSync(dirPath).isDirectory();
        if (isDir) {
            readFile(distP, dirPath, fileInfoList)
            return;
        }
        const content = readFileSync(dirPath);
        const hash = crypto.createHash('sha256');
        hash.update(content);
        const hashContent = hash.digest('hex');

        const filePath = relative(distP, dirPath); // 绝对路径 -> 相对路径
        fileInfoList.push({
            path: filePath,
            hash: hashContent,
            size: content.length,
        });
    });
}

function relative(from, to) {
    const p = path.relative(from, to).replace(/\/g, '/');
    if (/^[\w_]/.test(p)) {
        return './' + p;
    }
    return p;
}

完整代码 : https://github.com/UU-GIT/vite-plugin-hot-hash ⭐️ 欢迎 star ⭐️

三、本地调试

1.打包插件

npm run buid

// 为了方便调式, 开发时可执行: 
npm run dev

来看看, 生成了哪些文件

dist
├── index.mjs         # esm
├── index.d.ts        # 类型定义
└── index.js          # cjs

2.生成软连接

在当前目录执行npm link 在全局生成一个软连接,指向当前项目

3.项目注入

在自己vite项目中 执行:

npm link vite-plugin-hot-hash

然后我们可以看到 node_modules 中出现了vite-plugin-hot-hash符号链接.
Image.png

4.项目配置

在Vite项目的vite.config.js配置文件中加入插件

import HotHash from 'vite-plugin-hot-hash'; // import 方式(二选一)
// const { HotHash } = require('vite-plugin-hot-hash'); // require方式(二选一)

const { version } = require('./package.json');

export default defineConfig(({ mode }) => {
    retrun {
        plugins: [
            ...,
            HotHash({ version }),
            ...
        ],
    }
})

5.项目打包验证

npm run build

Image.png

Image.png

6.取消全局链接

当我们调试结束, 就可以解除软连接了, 可以在项目根目录下执行:

npm unlink vite-plugin-hot-hash

四、插件发布

1.注册账号

先去npm(https://www.npmjs.com/)注册账号

2.终端命令, 登录npm账号

npm login

Image.png

3.发布

npm publish

Image.png

五、插件钩子简介

1.通用钩子

在开发中, Vite 开发服务器会创建一个插件容器来调用 Rollup 构建钩子:

  • 服务器启动时被调用:

    • options
    • buildStart
  • 每个传入模块请求时被调用:

    • resolveId
    • load
    • transform
  • 服务器关闭时被调用:

    • buildEnd
    • closeBundle

详细说明及使用情况, 可查看rollup.js 文档说明: https://rollupjs.org/guide/en/

2.vite 独有钩子

详细说明及使用情况,可查看vite官方文档说明:

  • enforce : pre | post , pre 先执行;
  • apply : build | serve , 指明调用模式
  • config(config, { mode, command}) : 在解析 Vite 配置前调用. 钩子接收原始用户配置 和一个描述配置环境的变量, 包含正在使用的 modecommand.
  • configResolved(config) : 在解析 Vite 配置后调用. 使用这个钩子读取和存储最终解析的配置. 当插件需要根据运行的命令做一些不同的事情时, 它也很有用.
  • configureServer(server) : 用于配置开发服务器的钩子
  • configurePreviewServer(server): 与 configureServer 相同但是作为预览服务器. 它提供了一个 connect 服务器实例及其底层的 http server.
  • transformIndexHtml(html) : 转换 index.html 的专用钩子. 钩子接收当前的 HTML 字符串和转换上下文; * handleHotUpdate(ctx): 执行自定义 HMR 更新处理. 钩子接收一个带有以下签名的上下文对象: modules, read

源码地址: vite-plugin-hot-hashgithub: https://github.com/UU-GIT/vite-plugin-hot-hash
⭐️ 欢迎 star ⭐️

参考

https://cn.vitejs.dev/guide/api-plugin.html#universal-hooks
https://rollupjs.org/guide/en/

© 版权声明
THE END
喜欢就支持一下吧
点赞9 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容