在 vite 中基于 node 实现 simple-auto-import 插件

简介: 在 vite 中基于 node 实现 simple-auto-import 插件

image.png


前言

最近在通过 vite 简单的创建了 handWritten 项目,主要就是用于实现和记录一些关于 JavaScript 手写相关的内容,起初为了简单没有集成 Vitest主要还是不太想写测试用例)。

项目文件导入关系如下:

  • handWritten\src\code 目录下实现对应的功能
  • handWritten\src\code\index.ts 中统一导入对应的文件
  • handWritten\src\main.ts 中导入 indext.ts

最终在浏览器上观察对应的输出或展示结果,为什么不在 node 中查看呢?因为有些实现的效果是基于 dom 的,所以在浏览器上查看最终的结果会更方便些.

随着实现的功能越来越多(通常一个功能对应一个文件),需要手动导入的文件也越来越多,其实社区中已经有不少的实现方案,但很多东西还是需要自己动手实现才能有更深入的理解、才不会只局限于 API 的使用,于是就花了点时间基于 node 实现这个自动导入的功能.

当然还是需要先简单了解下 vite 插件相关的前置知识内容.

Vite 插件

插件类型

vite 中可用的插件分两种:

  • 插件命名通常 是一个带 vite-plugin- 前缀
  • 插件命名通常 是一个带 rollup-plugin- 前缀

如果对应插件只适用于特定的框架,那么需要在增加对应框架的名称:

  • vite-plugin-vue- 前缀作为 Vue 插件
  • vite-plugin-react- 前缀作为 React 插件
  • vite-plugin-svelte- 前缀作为 Svelte 插件

插件钩子

通用钩子

在开发中,Vite 开发服务器会创建一个插件容器来调用 Rollup 构建钩子,这类钩子在 rollupvite 中都可以使用.

服务器启动时被调用

每个传入模块请求时被调用

服务器关闭时被调用

Vite 独有钩子

Vite 插件中也可以设置只为 Vite 提供特定钩子用于实现特定目标,这些会被 Rollup 忽略.

  • config:在解析 Vite 配置前调用
  • configResolved:在解析 Vite 配置后调用
  • configureServer:是用于配置开发服务器的钩子,一般用于添加自定义中间件
  • transformIndexHtml:转换 index.html 的专用钩子,会接收当前的 HTML 字符串和转换上下文
  • handleHotUpdate:执行自定义 HMR 更新处理,钩子会接收一个上下文对象

插件执行顺序

Vite 插件可以额外指定一个 enforce 属性来调整插件的执行顺序,enforce 的值可以是prepost.

解析后的插件将按照以下顺序排列:

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

实现自定义插件 autoImport

定位插件类型

首先 自动导入 功能肯定不属于 Vite 独有的,也不属于 框架特有的,因此,这个插件的在定位上应该要作为 兼容 Rollup 的插件,于是我们可以给它命名为 rollup-plugin-auto-import,但是后来发现这个插件名称已经被使用了,为了避免混淆将其重新命名为:rollup-plugin-simple-auto-import.

核心功能分析

为了方便介绍和演示,这里就只要针对两个核心功能做实现即可:

  • 监听 src\code 目录下文件的新增、重命名、删除等操作
  • 根据具体的文件操作,做不同的处理
  • 对新增、重命名的文件,自动在 src\code\index.ts 中进行导入
  • 对删除的文件,自动在 src\code\index.ts 中进行剔除

核心功能实现

监听 src\code 目录下的文件变化

node 中可以通过 fs.watch() 来监听对应目录下文件的变化,值得注意的是当对应目录下文件被新增、重命名、删除时,其对应的回调函数接收到的 eventTyoe === 'rename' 和 当前文件的命名 filename

// 监听对应目录下文件的变化
function watchFile(dirPath) {
  fs.watch(
    dirPath,
    {
      encoding: "utf-8",
    },
    (eventType, filename) => {
      // 重命名文件、新增文件、删除文件时触发
      if (eventType === "rename") {
        console.log("监听到文件的变化了");
      }
    }
  );
}
复制代码

文件变化时自动处理

  • 对新增、重命名的文件,自动在 src\code\index.ts 中进行导入
  • 对删除的文件,自动在 src\code\index.ts 中进行剔除

node 中可以通过 fs.exists() 来判断是否存在对应的文件,但在官方文档中已经被废弃了:

image.png

这里我们通过 fs.access() 来代替 fs.exists() 实现对应的功能:

// 监听对应目录下文件的变化
function watchFile(dirPath) {
  fs.watch(
    dirPath,
    {
      encoding: "utf-8",
    },
    (eventType, filename: string) => {
      // 重命名文件、新增文件、删除文件时触发
      if (eventType === "rename") {
        const filePath = path.join(defaultDirPath, `/${filename}`);
        fs.access(filePath, (error: any) => {
          // 判断是否存在对应文件
          if (error) {
            // 不存在文件则将对应文件的导入语句清除
            const repalceStr = `import "./${filename}"`;
            rewriteFile(repalceStr, "");
          } else {
            // 存在对应文件则向目标文件添加导入语句
            const appendContent = `\nimport "./${filename}"`;
            appendFile(appendContent);
          }
        });
      }
    }
  );
}
复制代码

rewriteFile 方法

该方法主要负责对 src\codes\index.ts 文件进行重写,针对被删除的文件,需要将原本导入的语句进行删除,内容比较简单:

// 重写文件内容
function rewriteFile(repalceStr, content) {
  const rawContent = fs.readFileSync(defaultImportPath, { encoding: "utf8" });
  fs.writeFileSync(defaultImportPath, rawContent.replace(repalceStr, content));
}
复制代码

appendFile 方法该方法是基于 src\codes\index.ts 文件的原有内容,添加对新增、重命名文件导入语句,内容也比较简单:

// 追加文件内容
function appendFile(appendContent) {
  fs.appendFile(defaultImportPath, appendContent, function (error) {
    if (error) {
      console.log("~ 自动导入文件【失败】 ~");
      return;
    }
    console.log("~ 自动导入文件【成功】 ~");
  });
}
复制代码

定义插件

有了核心功能的实现,最后只需要将这个核心功能定义为 vite 能识别的插件形式就可以了,具体内容在 src\plugins\autoImport.ts 中:

export default function () {
  return {
    name: "rollup-plugin-simple-auto-import",
    apply: "serve", // 指明它们仅在 'build' 或 'serve' 模式时调用
    buildStart() {
      watchFile(defaultDirPath);
    },
  };
}
复制代码

核心演示效果

image.png

最后

这里只是实现了最基本的核心功能,还可以扩展出其他更多的内容,但从实现过程上来看需要了解不算少的前置知识,这也是一个能够让我们学到更多的一个过程,具体代码可查看 源代码.


目录
相关文章
|
6月前
|
JavaScript 前端开发 安全
使用 Node.js 插件给指定目录下的所有图片添加上文字水印
使用 Node.js 插件给指定目录下的所有图片添加上文字水印
156 0
|
6月前
|
JavaScript 前端开发
nodejs实现解析chm文件列表,无需转换为PDF文件格式,在线预览chm文件以及目录,不依赖任何网页端插件
nodejs实现解析chm文件列表,无需转换为PDF文件格式,在线预览chm文件以及目录,不依赖任何网页端插件
|
6月前
|
Kubernetes 应用服务中间件 Docker
Kubernetes学习-集群搭建篇(二) 部署Node服务,启动JNI网络插件
Kubernetes学习-集群搭建篇(二) 部署Node服务,启动JNI网络插件
|
4月前
|
JavaScript IDE 开发工具
vue3【2024版】开发环境搭建(含官网和nvm下载切换最新版node,修改node下载源,创建项目,启动项目,安装vscode插件Vue - Official)
vue3【2024版】开发环境搭建(含官网和nvm下载切换最新版node,修改node下载源,创建项目,启动项目,安装vscode插件Vue - Official)
252 3
|
6月前
|
SQL 前端开发 JavaScript
前端vite+vue3结合后端node+koa——实现代码模板展示平台(支持模糊搜索+分页查询)
前端vite+vue3结合后端node+koa——实现代码模板展示平台(支持模糊搜索+分页查询)
150 4
|
12月前
|
消息中间件
RabbitMq没开启rabbitmq_management插件控制台报错Node statistics not available
RabbitMq没开启rabbitmq_management插件控制台报错Node statistics not available
|
6月前
|
SQL Prometheus 监控
助力工业物联网,工业大数据之服务域:node_exporter插件【三十七】
助力工业物联网,工业大数据之服务域:node_exporter插件【三十七】
75 1
|
编解码
node封装一个图片拼接插件
node封装一个图片拼接插件
122 0
|
移动开发 算法 前端开发
node封装一个控制台进度条插件
node封装一个控制台进度条插件
132 0
|
SQL 前端开发 关系型数据库
express中使用node-xlsx插件下载excel表格
express中使用node-xlsx插件下载excel表格
282 0