2

Vite 相对于 Webpack 上手难度小,简单的配置,开箱即用。虽然目前生态不如 Webpack,不过生态也逐渐的丰富起来。

经过了一些 Vite 插件编写实践,今天来说说虚拟模块(Virtual Modules ),也顺便介绍下 vite-plugin-project-info 插件。

虚拟模块的概念

虚拟模块是 Vite 沿用 Rollup 的虚拟模块,虚拟模块类似 alias 别名,但是模块的内容并非直接从磁盘中读取,而是编译时生成。

虚拟模块是一种很实用的模式,使你可以对使用 ESM 语法的源文件传入一些编译时信息。

虚拟模块实现例子

首先你可能需要先了解插件编写的 API

这里直接搬运官网的例子:

export default function myPlugin() {
  const virtualModuleId = 'virtual:my-module'
  const resolvedVirtualModuleId = '\0' + virtualModuleId

  return {
    name: 'my-plugin',
    resolveId(id) {
      if (id === virtualModuleId) {
        return resolvedVirtualModuleId
      }
    },
    load(id) {
      if (id === resolvedVirtualModuleId) {
        return `export const msg = "from virtual module"`
      }
    }
  }
}

然后代码中引入这些模块:

import { msg } from 'virtual:my-module'

console.log(msg)

实践分析: vite-plugin-project-info

vite-plugin-project-info 是 Vite 项目信息插件,使用后会在 Conole 面板输出版本、构建时间等信息。

配合虚拟模块实现插件

  1. resolveId 钩子函数:真实虚拟模块 ID 转换为内部虚拟模块 ID。
  2. load 钩子函数:匹配内部虚拟模块 ID,并返回编译时的代码,最终实现了 virtual:project-info 模块。
  3. transform 钩子函数:实现自动 import 功能

    截止第二步其实已经实现了虚拟模块的功能,但是我们

export default function projectInfoPlugin(opts: ProjectInfoPluginOptions = {}): PluginOption {
  const { entry = path.resolve('src/main'), locale } = opts;
  const lastEntry = entry.split('.')[0];
  const virtualModuleId = 'virtual:project-info';
  const resolvedVirtualModuleId = '\0' + virtualModuleId;

  return {
    name: 'vite:project-info',
    enforce: 'pre',
    resolveId(id) {
      if (id === virtualModuleId) {
        return resolvedVirtualModuleId;
      }
    },
    load(id) {
      if (id === resolvedVirtualModuleId) {
        return createCode({
          locale,
        });
      }
    },
    transform(code, id) {
      if (id.includes(path.resolve(lastEntry).replace(/\\/g, '/'))) {
        return {
          code: `import '${virtualModuleId}';\n${code}`,
          map: this.getCombinedSourcemap(),
        };
      }
    },
  };
}

功能使用

支持直接在浏览器 Console 中输出相关项目信息,同时支持如下代码使用:

import projectInfo from 'virtual:project-info';
console.log(projectInfo.version); // 版本信息
console.log(projectInfo.buildTime); // 构建时间
console.log(projectInfo.name); // 项目名称
console.log(projectInfo.description); // 项目描述
console.log(projectInfo.repository); // 仓库链接
console.log(projectInfo.author); // 项目负责人或者作者

Samon
1.3k 声望92 粉丝