vite浅析插件

发布时间 2023-11-17 17:35:05作者: 柯基与佩奇

前言

最近使用 vite 在写项目时,遇到vue3中给setup添加name的问题,本来是打算直接使用插件进行实现的,但是评论说是会有各种各样的问题,看了下vite插件介绍后,下面来讲解 Vite 插件的基本概念。

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 插件

插件结构

一般插件结构由 nameenforce钩子组成。

  • name:即插件名字。
  • enforce: 通过该属性来调整插件加载顺序,可选值:pre | post
  • 钩子:不同状态下对应的处理函数,类似于生命周期。

image.png

插件加载顺序

插件结构中 enforce属性可调整插件加载顺序,Vite 插件加载顺序如下:

  • Alias
  • 带有  enforce: 'pre'  的用户插件
  • Vite 核心插件(解析 vue 文件等)
  • 没有 enforce 值的用户插件
  • Vite 构建用的插件
  • 带有  enforce: 'post'  的用户插件
  • Vite 后置构建插件(最小化,manifest,报告)

image.png

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

image.png

Vite 插件钩子

通用钩子

服务器启动钩子:

options

options 钩子主要是获取 Rollup 的配置,由于 vite 开发的时候使用的是 EsBuild,所以开发环境下该属性为空,主要包含一些使用的 plugin,input入口文件等。

示例代码:

export function testPlugin() {
  return {
    //插件名字
    name: "vite-plugin-test",
    options(options) {
      //可设置options.input修改入口文件
      console.log(options);
    },
  };
}

image.png

buildStart

buildStart 钩子执行顺序在options钩子后,主要是获取options钩子配置后的Rollup 配置和一些默认值,这个钩子开发和生产环境值都存在,不同于options,通过该钩子可以清楚看到Vite 开发环境下对Rollup做的兼容模拟。

示例代码:

export function testPlugin() {
  return {
    //插件名字
    name: "vite-plugin-test",
    buildStart(options) {
      console.log(options);
    },
  };
}

开发环境下:

image.png

生产环境时:

image.png

加载模块请求时钩子:

resolveId

resolveId 钩子可以获取文件路径,在该钩子下可以对文件路径进行重写或其他操作。

设置 enforce 不同值所打印的也不同哦

示例代码:

export function testPlugin() {
  return {
    //插件名字
    name: "vite-plugin-test",
    resolveId(id) {
      console.log(id);
    },
  };
}

image.png

load

load 钩子可拦截文件读取,模块引入读取操作,参数和resolveId 钩子类似,如需替换模块读取内容,返回对应codemap即可。

示例代码:

export function testPlugin() {
  return {
    //插件名字
    name: "vite-plugin-test",
    load(id) {
      console.log(id);
      if (id === "xxxx") {
        return {
          code: "<template>xxxxx</template>",
          map: "",
        };
      }
    },
  };
}

image.png

transform

transform 钩子可以转换单个模块对应的代码,和 load 钩子不同的是,他有两个参数,codeid,这里的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:

image.png

空或 post:

image.png

服务器关闭钩子:

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 的基本配置,第二个参数包括当前modecommand

示例代码:

export function testPlugin() {
  return {
    //插件名字
    name: "vite-plugin-test",
    config: (config, { mode, command }) => {
      console.log(config);
      console.log(mode);
      console.log(command);
    },
  };
}

image.png

configResolved

configResolved 钩子是解析 Vite 默认配置后钩子,返回的是最终的 Vite 配置(自定义配置合并后的),可用于获取当前的一些配置,根据不同配置做不同的事情。

示例代码:

export function testPlugin() {
  return {
    //插件名字
    name: "vite-plugin-test",
    configResolved(config) {
      console.log(config);
    },
  };
}

image.png

configureServer

configureServer 是配置开发服务器钩子,仅在开发环境下才会执行,他会返回当前开发服务器的配置。

示例代码:

export function testPlugin() {
  return {
    //插件名字
    name: "vite-plugin-test",
    configureServer(config) {
      console.log(config);
    },
  };
}

image.png

configurePreviewServer

configurePreviewServer钩子和configureServer类似,但是configurePreviewServer是预览服务器,仅在执行npm run preview时触发该钩子。

示例代码:

export function testPlugin() {
  return {
    //插件名字
    name: "vite-plugin-test",
    configureServer(config) {
      console.log(config);
    },
  };
}

image.png

transformIndexHtml

transformIndexHtml钩子主要是操作index.html文件,它会返回当前的html文件,修改index.htmltitle就可以在该钩子中修改。

示例代码:

export function testPlugin() {
  return {
    //插件名字
    name: "vite-plugin-test",
    transformIndexHtml(html) {
      console.log(html);
    },
  };
}

image.png

handleHotUpdate

handleHotUpdate 钩子主要是热更新钩子,这里就略过。