今天想试着写一个vite 插件,在网上找了很多案例。
找到了这个文档,今天把他简化一下 Vite 实战:手把手教你写一个 Vite 插件 - 掘金 (juejin.cn)
创建一个测试文件
这里我们把替换俩个字换成 下面的 md 文件里面的内容
开始看代码
我们先在 vue.config.js 里面把 文件引入
import markdownPlugin from './cs.cjs'
plugins: [
markdownPlugin()
],
cs.cjs
// 我们先简单介绍一下,插件的各个函数
/**
*
* @param {*} customOptions 穿进来的配置
* @returns
*/
function vitePluginStyleVWLoader (customOptions) {
return {
// 插件名称
name: "vite-plugin-style-vw-loasadasdder",
/**
* build: 在 Vite 构建时调用
* serve: 在 Vite 加载模块时调用
* 默认: 都会调用
*/
apply: 'build',
/** 强制插件排序
* pre 在 Vite 核心插件之前调用该插件
* post 在 Vite 核心插件之后调用该插件
* 默认: post
*/
enforce: 'post', //在 Vite 核心插件之前调用该插件(就是在vite没有编译化代码前调用,) || post在 Vite 构建插件之后调用该插件
/**
* closeBundle:
* 在 `vite` 本地服务关闭前,`rollup` 输出文件到目录前调用
* (白话文:就是 build 打包之后调用的钩子函数)
*/
closeBundle: {
sequential: true,
async handler () {
// console.log(zipName[0])
console.log('');
}
},
/**
*handleHotUpdate 热更新 在 src 下面的文件中修改就会执行
* @param {*} file file 修改的文件路径
* @param {*} server vite 服务实例 返回 的是个 map对象
* @param {*} modules 修改的文件对应的模块
*/
handleHotUpdate (ctx) {
const { file, server, modules } = ctx;
},
/**
*修改了引用文件的,=返回对应的参数
* @param {*} code :文件的源码字符串
* @param {*} id 文件的路径path
* @param {*} opt
* @returns {ssr:boolean} 我也不知道是啥,说是在编译和
*/
transform (code, id, opt) {
return { code };
}
}
}
module.exports = vitePluginStyleVWLoader;
代码实现
Vite 实战:手把手教你写一个 Vite 插件 - 掘金 (juejin.cn)
这个博主是实现了一个组件,把md 文件引入进去。我们这个把文字替换成 md 文件里面的内容
// 当文件变化的时候,会优先执行 transform 钩子函数
transform (code, id, opt) {
const template = /<template\b[^>]*>[\s\S]*<\/template>/g;
// 这里犯个懒,这里应该是用正则筛选出 是不是 vue文件,简单的写死了路径
if (id !== 'D:/ZHUO MIAN/V3/my+ts/src/views/CeShi/index.vue') return code;
//这里拿到了 修改的 vue 文件里面的内容,筛选出 template 标签里面的字符串,进行替换,返回出去即可
const mdList = code.match(template);
const readdirSync = file.readFileSync('D:/ZHUO MIAN/V3/my+ts/src/views/CeShi/as.md', 'utf-8',);
const res = mdList[0].replace(/替换/g, readdirSync);
let transformCode = code.replace(template, res);
return transformCode;
}
但是,我们的vue 文件改变了,vite 会热更新,但是引用的 md 文件就不会热i更新了。
transform 只会触发被 引入在页面的文件
那么 handleHotUpdate 函数就出厂了。他会把 src 下面所有的修改对的文件都会触发
handleHotUpdate (ctx) {
const { file, server, modules } = ctx;
// 过滤非 md 文件
if (file !== 'D:/ZHUO MIAN/V3/my+ts/src/views/CeShi/as.md') return;
// 找到引入该 md 文件对应的 vue 文件
const relationId = 'D:/ZHUO MIAN/V3/my+ts/src/views/CeShi/index.vue';
// 找到该 vue 文件的 moduleNode 返回的是个 map 对象需要拿到里面的参数
const relationModule = [...server.moduleGraph.getModulesByFile(relationId)][0];
/** 发送 websocket 消息,进行单文件热重载
* type: 'update' 更新
* updates: [
* {
* type: 'js-update' js更新
* path: relationModule.file 修改的文件路径
* acceptedPath: relationModule.file 修改的文件路径
* timestamp: new Date().getTime() 时间戳
* }
* ]
*/
server.ws.send({
type: 'update',
updates: [
{
type: 'js-update',
path: relationModule.file,
acceptedPath: relationModule.file,
timestamp: new Date().getTime()
}
]
});
// 指定需要重新编译的模块
return [...modules, relationModule]
},
这样就完成了。
全部代码
/* eslint-disable */
const path = require('path');
const file = require('fs');
// const MarkdownIt = require('markdown-it');
// import { Plugin } from 'vite'
function markdownPlugin () {
const template = /<template\b[^>]*>[\s\S]*<\/template>/g;
return {
// 插件名称
name: 'vite:markdown',
// 该插件在 plugin-vue 插件之前执行,这样就可以直接解析到原模板文件
enforce: 'pre',
/**
*handleHotUpdate 热更新 在 src 下面的文件中修改就会执行
* @param {*} file file 修改的文件路径
* @param {*} server vite 服务实例 返回 的是个 map对象
* @param {*} modules 修改的文件对应的模块
*/
handleHotUpdate (ctx) {
const { file, server, modules } = ctx;
// 过滤非 md 文件
if (file !== 'D:/ZHUO MIAN/V3/my+ts/src/views/CeShi/as.md') return;
// 找到引入该 md 文件的 vue 文件
const relationId = 'D:/ZHUO MIAN/V3/my+ts/src/views/CeShi/index.vue';
// 找到该 vue 文件的 moduleNode
const relationModule = [...server.moduleGraph.getModulesByFile(relationId)][0];
/** 发送 websocket 消息,进行单文件热重载
* type: 'update' 更新
* updates: [
* {
* type: 'js-update' js更新
* path: relationModule.file 修改的文件路径
* acceptedPath: relationModule.file 修改的文件路径
* timestamp: new Date().getTime() 时间戳
* }
* ]
*/
server.ws.send({
type: 'update',
updates: [
{
type: 'js-update',
path: relationModule.file,
acceptedPath: relationModule.file,
timestamp: new Date().getTime()
}
]
});
// 指定需要重新编译的模块
return [...modules, relationModule]
},
// 代码转译,这个函数的功能类似于 `webpack` 的 `loader`
transform (code, id, opt) {
if (id !== 'D:/ZHUO MIAN/V3/my+ts/src/views/CeShi/index.vue') return code;
const mdList = code.match(template);
const readdirSync = file.readFileSync('D:/ZHUO MIAN/V3/my+ts/src/views/CeShi/as.md', 'utf-8',);
const res = mdList[0].replace(/替换/g, readdirSync);
let transformCode = code.replace(template, res);
return transformCode;
}
}
}
// overwrite for cjs require('...')() usage
module.exports = markdownPlugin
markdownPlugin['default'] = markdownPlugin