十七.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