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文件夹, 并且默认是符合commonJS的cjs格式
- --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;
}
完整代码 : github.com/UU-GIT/vite… ⭐️ 欢迎 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符号链接.

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


6.取消全局链接
当我们调试结束, 就可以解除软连接了, 可以在项目根目录下执行:
npm unlink vite-plugin-hot-hash
四、插件发布
1.注册账号
2.终端命令, 登录npm账号
npm login

3.发布
npm publish

五、插件钩子简介
1.通用钩子
在开发中, Vite 开发服务器会创建一个插件容器来调用 Rollup 构建钩子:
- 
服务器启动时被调用: - options
- buildStart
 
- 
每个传入模块请求时被调用: - resolveId
- load
- transform
 
- 
服务器关闭时被调用: - buildEnd
- closeBundle
 
详细说明及使用情况, 可查看rollup.js 文档说明: rollupjs.org/guide/en/
2.vite 独有钩子
详细说明及使用情况,可查看vite官方文档说明:
- enforce:- pre|- post,- pre先执行;
- apply:- build|- serve, 指明调用模式
- config(config, { mode, command}): 在解析- Vite配置前调用. 钩子接收原始用户配置 和一个描述配置环境的变量, 包含正在使用的- mode和- command.
- configResolved(config): 在解析- Vite配置后调用. 使用这个钩子读取和存储最终解析的配置. 当插件需要根据运行的命令做一些不同的事情时, 它也很有用.
- configureServer(server): 用于配置开发服务器的钩子
- configurePreviewServer(server): 与- configureServer相同但是作为预览服务器. 它提供了一个- connect服务器实例及其底层的- http server.
- transformIndexHtml(html): 转换- index.html的专用钩子. 钩子接收当前的- HTML字符串和转换上下文; *- handleHotUpdate(ctx): 执行自定义- HMR更新处理. 钩子接收一个带有以下签名的上下文对象:- modules,- read
源码地址: vite-plugin-hot-hash - github: github.com/UU-GIT/vite…
⭐️ 欢迎 star ⭐️
参考
转载自:https://juejin.cn/post/7173858168865308685




