十七.vite之浅析插件篇
前言
最近使用vite在写项目时,遇到vue3中给setup添加name的问题,本来是打算直接使用插件进行实现的,但是评论说是会有各种各样的问题,看了下vite插件介绍后,突发奇想要不自己写一个?说干就干,下面来讲解Vite插件的基本概念。
vue3-basic-admin,该项目是一款开源开箱即用的中后台管理系统。基于
Vue3、Vite、Element-Plus、TypeScript、Pinia等主流技术开发,内置许多开箱即用的组件,能快速构建中后台管理系统。
Vite和Rollup
有了解过Vite的都知道,Vite开发用的 ESBuild,而生产打包的时候使用的 Rollup进行打包,可能有人会有疑问,为什么生产不直接用 ESBuild 打包而是用 Rollup,对此Vite官方是这样回复的:
虽然 esbuild 快得惊人,并且已经是一个在构建库方面比较出色的工具,但一些针对构建 应用 的重要功能仍然还在持续开发中 —— 特别是代码分割和 CSS 处理方面。就目前来说,Rollup 在应用打包方面更加成熟和灵活。尽管如此,当未来这些功能稳定后,我们也不排除使用 esbuild 作为生产构建器的可能。
可以理解为 Vite用Esbuild来干活,干完活就不用它了,换成Rollup进行打包。
Vite之所以能开发和生产使用两套不同的构建工具,是因为他在dev环境下,其实是通过插件容器,除了使用Vite独有特性的插件,其他插件会进行模拟 Rollup插件行为,等到打包的时候,会将这一块替换成 Rollup 打包,所以其实不管是开发环境还是生产环境其实共享的同一套 Rollup插件机制,Vite插件 相当于是对 Rollup插件 做了一层兼容,或者换一个说法,Vite插件对Rollup插件做了扩展,加上了一些Vite独有的属性。
Vite插件概念
命名规范
如不使用Vite独有特性,可当做兼容Rollup的插件,推荐以推荐使用 Rollup 插件名称约定,反之,推荐以 vite-plugin- 开头,如果专属于某个框架,推荐格式:
vite-plugin-vue-前缀作为 Vue 插件vite-plugin-react-前缀作为 React 插件
插件结构
一般插件结构由 name、enforce 和钩子组成。
- name:即插件名字。
- enforce: 通过该属性来调整插件加载顺序,可选值:
pre | post - 钩子:不同状态下对应的处理函数,类似于生命周期。

插件加载顺序
插件结构中 enforce属性可调整插件加载顺序,Vite 插件加载顺序如下:
- Alias
- 带有
enforce: 'pre'的用户插件 - Vite 核心插件(解析vue文件等)
- 没有 enforce 值的用户插件
- Vite 构建用的插件
- 带有
enforce: 'post'的用户插件 - Vite 后置构建插件(最小化,manifest,报告)

这里借用一张rollup的执行顺序:

Vite插件钩子
通用钩子
服务器启动钩子:
options
options 钩子主要是获取Rollup的配置,由于vite开发的时候使用的是EsBuild,所以开发环境下该属性为空,主要包含一些使用的 plugin,input入口文件等。
示例代码:
export function testPlugin(){
return {
//插件名字
name:'vite-plugin-test',
options(options) {
//可设置options.input修改入口文件
console.log(options)
}
}
}

buildStart
buildStart 钩子执行顺序在options钩子后,主要是获取options钩子配置后的Rollup 配置和一些默认值,这个钩子开发和生产环境值都存在,不同于options,通过该钩子可以清楚看到Vite开发环境下对Rollup做的兼容模拟。
示例代码:
export function testPlugin(){
return {
//插件名字
name:'vite-plugin-test',
buildStart(options) {
console.log(options)
}
}
}
开发环境下:

生产环境时:

加载模块请求时钩子:
resolveId
resolveId 钩子可以获取文件路径,在该钩子下可以对文件路径进行重写或其他操作。
设置 enforce 不同值所打印的也不同哦
示例代码:
export function testPlugin(){
return {
//插件名字
name:'vite-plugin-test',
resolveId(id) {
console.log(id)
}
}
}

load
load钩子可拦截文件读取,模块引入读取操作,参数和resolveId钩子类似,如需替换模块读取内容,返回对应code和map即可。
示例代码:
export function testPlugin(){
return {
//插件名字
name:'vite-plugin-test',
load(id) {
console.log(id)
if(id==='xxxx'){
return {
code:'<template>xxxxx</template>',
map:''
}
}
}
}
}

transform
transform钩子可以转换单个模块对应的代码,和load钩子不同的是,他有两个参数,code和id,这里的id和上面一样,这个code就是他对应的代码 ,简单情况下可直接修改 code去实现,复杂情况还是需要通过解析工具去解析vue。给setup加name就是用这个钩子实现的,这个我们在下一篇详细讲解。
这里注意,enforce设置的不同会导致code不同,如设置成pre这是编译前源代码,为空或post则是编译后的代码。
示例代码:
export function testPlugin(){
return {
//插件名字
name:'vite-plugin-test',
transform(code,id){
if(id.includes('HelloWorld')){
console.log(code)
}
console.log(id)
}
}
}
pre:

空或post:

服务器关闭钩子:
buildEnd
buildEnd钩子是打包代码生成之前触发的钩子,仅在生产环境生效。
示例代码:
export function testPlugin(){
return {
//插件名字
name:'vite-plugin-test',
buildEnd(){
}
}
}
closeBundle
closeBundle 钩子是打包后最后执行的钩子,他和buildEnd的区别是,它是打包代码生成后触发的钩子。
示例代码:
export function testPlugin(){
return {
//插件名字
name:'vite-plugin-test',
closeBundle(){
}
}
}
Vite独有钩子(以下钩子会被Rollup忽略)
config
config钩子是解析Vite默认配置前钩子,它返回了Vite的一些默认配置,可以在这里修改配置,它有两个参数,第一个参数config是Vite的基本配置,第二个参数包括当前mode和command
示例代码:
export function testPlugin(){
return {
//插件名字
name:'vite-plugin-test',
config:(config,{mode,command})=>{
console.log(config)
console.log(mode)
console.log(command)
}
}
}

configResolved
configResolved钩子是解析Vite默认配置后钩子,返回的是最终的Vite配置(自定义配置合并后的),可用于获取当前的一些配置,根据不同配置做不同的事情。
示例代码:
export function testPlugin(){
return {
//插件名字
name:'vite-plugin-test',
configResolved(config) {
console.log(config)
},
}
}

configureServer
configureServer 是配置开发服务器钩子,仅在开发环境下才会执行,他会返回当前开发服务器的配置。
示例代码:
export function testPlugin(){
return {
//插件名字
name:'vite-plugin-test',
configureServer(config) {
console.log(config)
},
}
}

configurePreviewServer
configurePreviewServer钩子和configureServer类似,但是configurePreviewServer是预览服务器,仅在执行npm run preview时触发该钩子。
示例代码:
export function testPlugin(){
return {
//插件名字
name:'vite-plugin-test',
configureServer(config) {
console.log(config)
},
}
}

transformIndexHtml
transformIndexHtml钩子主要是操作index.html文件,它会返回当前的html文件,修改index.html的title就可以在该钩子中修改。
示例代码:
export function testPlugin(){
return {
//插件名字
name:'vite-plugin-test',
transformIndexHtml(html) {
console.log(html)
},
}
}

handleHotUpdate
handleHotUpdate 钩子主要是热更新钩子,感兴趣可以去看下Vite热更新原理,这里就略过。
总结
以上就是Vite插件的一些基本概念,实际开发中可以根据这些不同的钩子去实现很多很有意义的功能,下一篇我们开始对这些钩子进行实战,敬请期待。
其他文章
转载自:https://juejin.cn/post/7210245454637629497