Vite: 插件开发

概述

  • 说到自定义的能力,肯定很容易想到 插件机制 ,利用一个个插件来扩展构建工具自身的能力
  • 虽然 Vite 的插件机制是基于 Rollup 来设计的,但实际上 Vite 的插件机制也包含了自己独有的一部分,与Rollup 的各个插件 Hook 并非完全兼容
  • 因此我们重点关注 Vite 独有的部分以及和 Rollup 所区别的部分,而对于 Vite 和 Rollup 中相同的 Hook (如 resolveId 、load 、 transform )只是稍微提及,就不再展开赘述

一个简单的插件示例

  • Vite 插件与 Rollup 插件结构类似,为一个 name 和各种插件 Hook 的对象
    {
         
         
    	 // 插件名称
    	 name: 'vite-plugin-xxx',
    	 load(code) {
         
         
    	 	// 钩子逻辑
    	 },
    }
    
  • 如果插件是一个 npm 包,在 package.json 中的包命名也推荐以 vite-plugin 开头
  • 一般情况下因为要考虑到外部传参,我们不会直接写一个对象,而是实现一个返回插件对象的 工厂函数,如下代码所示
    // myPlugin.js
    export function myVitePlugin(options) {
         
         
    	 console.log(options)
    	 return {
         
         
    		 name: 'vite-plugin-xxx',
    		 load(id) {
         
         
    		 	// 在钩子逻辑中可以通过闭包访问外部的 options 传参
    		 }
    	 }
    }
    
    // 使用方式
    // vite.config.ts
    import {
         
          myVitePlugin } from './myVitePlugin';
    export default {
         
         
     plugins: [myVitePlugin({
         
          /* 给插件传参 */ })]
    }
    

插件 Hook


1 )通用 Hook

  • 在双引擎架构这一节中介绍过,Vite 开发阶段会模拟 Rollup 的行为
  • 其中 Vite 会调用一系列与 Rollup 兼容的钩子,这个钩子主要分为三个阶段:
    • 服务器启动阶段: options 和 buildStart 钩子会在服务启动时被调用
    • 请求响应阶段: 当浏览器发起请求时,Vite 内部依次调用 resolveId 、 load 和 transform 钩子
    • 服务器关闭阶段: Vite 会依次执行 buildEnd 和 closeBundle 钩子
  • 除了以上钩子,其他 Rollup 插件钩子(如 moduleParsed 、 renderChunk )均不会在Vite 开发阶段调用, 而生产环境下,由于 Vite 直接使用 Rollup,Vite 插件中所有 Rollup 的插件钩子都会生效

2 ) 独有 Hook

  • Vite 中特有的一些 Hook,这些 Hook 只会在 Vite 内部调用,而放到Rollup 中会被直接忽略

2.1 给配置再加点料: config

  • Vite 在读取完配置文件(即 vite.config.ts )之后,会拿到用户导出的配置对象,然后
    执行 config 钩子
  • 在这个钩子里面,你可以对配置文件导出的对象进行自定义的操作,如下代码所示:
    // 返回部分配置(推荐)
    const editConfigPlugin = () => ({
         
         
    	 name: 'vite-plugin-modify-config',
    	 config: () => ({
         
         
    		 alias: {
         
         
    		 	react: require.resolve('react')
    		 }
    	 })
    })
    
  • 官方推荐的姿势是在 config 钩子中返回一个配置对象,这个配置对象会和 Vite 已有的配
    置进行深度的合并
  • 不过你也可以通过钩子的入参拿到 config 对象进行自定义的修改,如下代码所示:
    const mutateConfigPlugin = () => ({
         
         
    	 name: 'mutate-config',
    	 // command 为 `serve`(开发环境) 或者 `build`(生产环境)
    	 config(config, {
         
          command }) {
         
         
    		 // 生产环境中修改 root 参数
    		 if (command === 'build') {
         
         
    		 	config.root = __dirname;
    		 }
    	 }
    })
    
  • 在一些比较深层的对象配置中,这种直接修改配置的方式会显得比较麻烦, 如 optimizeDeps.esbuildOptions.plugins ,需要写很多的样板代码,类似下面这样:
    // 防止出现 undefined 的情况
    config.optimizeDeps = config.optimizeDeps || {
         
         }
    config.optimizeDeps.esbuildOptions = config.optimizeDeps.esbuildOptions || {
         
         }
    config.optimizeDeps.esbuildOptions.plugins = config.optimizeDeps.esbuildOptions.plugins || []
    
  • 因此这种情况下,建议直接返回一个配置对象,这样会方便很多:
    config() {
         
         
     return {
         
         
    	 optimizeDeps: {
         
         
    		 esbuildOptions: {
         
         
    		 	plugins: []
    		 }
    	 }
     }
    }
    

2.2 记录最终配置: configResolved

  • Vite 在解析完配置之后会调用 configResolved 钩子,这个钩子一般用来记录最终的配置
    信息,而不建议再修改配置,用法如下所示:
const exmaplePlugin = () => {
   
   
	 let config
	 return {
   
   
		 name: 'read-config',
		 configResolved(resolvedConfig) {
   
   
			 // 记录最终配置
			 config = resolvedConfig
		 },
		 // 在其他钩子中可以访问到配置
		 transform(code, id) {
   
   
		 	console.log(config)
		 }
	 }
}

2.3 获取 Dev Server 实例: configureServer

  • 这个钩子仅在开发阶段会被调用,用于扩展 Vite 的 Dev Server,一般用于增加自定义 server 中间件,如下代码所示
const myPlugin = () => ({
   
   
	 name: 'configure-server',
	 configureServer(server) {
   
   
		 // 姿势 1: 在 Vite 内置中间件之前执行
		 server.middlewares.use((req, res, next) => {
   
   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wang's Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值