背景

最近在webpack项目里接入了Vite(dev mode),为开发提效。效果是真的猛。

项目启动速度提升70%-80%,HMR直接碾压webpack dev server

为了更加精准的计算收益,就需要将Vite启动相关的指标进行上报(启动时间,HMR,页面加载等等时间)

为此就要通过开发插件收集这些信息,然后通过埋点上报sdk上报到数据分析的平台

遇到的问题

通过查阅官方文档并未找到相关的钩子直接获取到这些指标

但在开发的时候添加 --debug就能很详细的看到所有资源的处理时间,HMR,详细的启动时间等等

{
"scripts": {
"dev": "vite --debug",
}
}
npm run dev

为此只能通过一些hack的手段获取这些指标了,下面将展开详细的介绍

期望

通过向目标工程引入插件,通过特定的回掉函数即可获取到debug模式下反馈的各种信息

准备工作

比较详细的介绍一下开发步骤

初始化工程

创建插件目录

mkdir vite-plugin-monitor

cd vite-plugin-monitor

初始化pkg.json

npm init -y

安装必要依赖

yarn add -D vite typescript @types/node rimraf

添加必要的两个指令dev,build,配置入口文件dist/index.js

{
"main": "dist/index.js",
"scripts": {
"dev": "tsc -w -p .",
"build": "rimraf dist && tsc -p ."
}
}

其中dev环境下添加了-w(--watch)参数,当文件有变动时,以便实时的进行更新

rimraf的作用是替代rm -rf指令,且是跨平台的,windows下同样生效

插件使用typescript开发,更有助于插件后续的维护

其中build直接使用typescript提供的默认tsc指令,对ts直接进行转换

根目录创建 tsconfig.json 内容如下

{
"compilerOptions": {
"target": "es2015",
"moduleResolution": "node",
"strict": false,
"declaration": true,
"noUnusedLocals": true,
"esModuleInterop": true,
"outDir": "dist",
"module": "commonjs",
"lib": ["ESNext","DOM"],
"sourceMap": true,
},
"include": ["./src"]
}

src 目录下进行开发,里面存放我们的源码

目录结构

最终目录如下

├── package.json
├── src
| ├── index.ts # 插件入口
| ├── types
| | └── index.ts # 类型定义
| └── utils
| └── index.ts # 工具方法
├── tsconfig.json

简单插件示例

根据插件开发文档,在src/index.ts文件下编写如下简单的代码;

  • name:标识插件的名称
  • apply:标识插件在哪个时期工作(serve|build),默认都会调用
  • config:这个钩子接收原始用户配置(命令行选项指定的会与配置文件合并)和一个描述配置环境的变量
import type { Plugin } from 'vite';

export default function Monitor(): Plugin {
return {
name: 'vite-plugin-monitor',
apply: 'serve',
config(userConfig, env) {
console.log(userConfig);
console.log(env)
// 可以做进一步的修改,会自动合入当前的配置
// return
},
};
}

一个打印Vite配置的插件就搞定了,下面就是测试我们开发的插件

本地测试插件

首先是转换我们的ts=> js ,执行前面配置的指令yarn dev,就会看见生成了一个dist目录,里面有转换后的代码

接着执行npm link在全局生成一个软连接,指向当前项目

npm link

在一个vite项目里的执行npm link vite-plugin-monitor(monitor根据实际情况替换),向目标项目加入此依赖

npm link vite-plugin-monitor

接着就可以在Vite项目的vite.config.js配置文件中加入我们的插件了

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vitePluginMonitor from 'vite-plugin-monitor' // https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
vitePluginMonitor()
]
})

接着通过配置的指令启动vite,就能看到我们插件的打印的配置文件内容了

由于是通过软连接的方式引入的插件,那么在插件工程里的任意更改都会实时生效,也就避免了频繁的执行yarn add file:localProjectDir

功能开发

有了前文的铺垫内容,下面就是功能开发

获取启动耗时

项目启动后会在终端中输出ready in xxms

为此咱们使用Vs Code在源码中搜一下这个关键字

可以看到此部分代码在源码中如下

const info = server.config.logger.info

// @ts-ignore
if (global.__vite_start_time) {
// @ts-ignore
const startupDuration = performance.now() - global.__vite_start_time
info(`\n ${chalk.cyan(`ready in ${Math.ceil(startupDuration)}ms.`)}\n`)
}

这个performance.now()等同于Date.now()即当前时间,通过global.__vite_start_time就能获取到服务启动时间

我们就从这个info方法入手,给它重定义一下,通过configureServer钩子可以获取到server实例

index.ts

import type { Plugin } from 'vite';

export default function Monitor(): Plugin {
const startTime = global.__vite_start_time return {
name: 'vite-plugin-monitor',
apply: 'serve',
configureServer(server) {
const { info } = server.config.logger;
// 拦截info方法的调用
server.config.logger.info = function _info(str) {
// 调用原info方法
info.apply(this, arguments);
// 通过字符串内容进行一个简单的判断
if (str.includes('ready in')) {
console.log('startupDuration', Date.now() - startTime)
}
};
},
};
}

启动一个项目看看效果,成了。

HMR时间获取

热更新时,终端中会出现下面的日志

同理源码里搜一搜,能够定位出如下内容

config.logger.info(
updates
.map(({ path }) => chalk.green(`hmr update `) + chalk.dim(path))
.join('\n'),
{ clear: true, timestamp: true }
)

暂以打印这个日志的时间作为HMR开始的时间

let startTime = null
const { info } = server.config.logger;
server.config.logger.info = function _info(str) {
info.apply(this, arguments);
if (str.indexOf('hmr update') >= 0) {
startTime = Date.now()
}
};

触发HMR时,客户端会发出一个获取资源的请求,请求携带了一个import参数,我们通过这个参数来标识这个特定的请求

http://localhost:8080/src/pages/home/index.vue?import&t=1632924377207

钩子中的server实例包含middlewares属性可以向上添加自定义的中间件处理方法

  • 通过URL实例解析search参数,然后判断是否包含import&
  • 重定义end方法,在资源传回到客户端后打印耗时
server.middlewares.use(async (req, res, next) => {
const { search } = new URL(req.url, `http://${req.headers.host}`);
if (
search.indexOf('import&') >= 0
) {
const { end } = res;
res.end = function _end() {
// 在资源返回后打印耗时
end.apply(this, arguments);
console.log(Date.now() - startTime)
};
}
next();
});

事实上通过--debug启动服务,能看到在HMR时会打印4个时间

目前方法仅仅得到了vite:hmr部分的时间,与实际耗时还有一丝丝差异

小结

本篇主要介绍了monitor插件开发的背景,要解决的问题,目标以及开发插件所需的一些列准备工作

功能开发介绍了启动时间与HMR时间的获取方式

更加详细的信息目前看来只能通过--debug看到,下一步的计划就是通过某种手段拿到debug下打印的日志内容

由于时间关系,这部分hack还没完成。准备假期抽时间实现一下。下一篇文章将详细的介绍最终实现。

Vite插件开发纪实:vite-plugin-monitor(上)的更多相关文章

  1. Vite插件开发纪实:vite-plugin-monitor(下)

    前言 上一篇介绍了Vite启动,HMR等时间的获取. 但各阶段详细的耗时信息,只能通过debug的日志获取 本文就实现一下debug日志的拦截 插件效果预览 --debug做了什么 项目启动指令 vi ...

  2. 使用 Vite 插件开发构建 Tampermonkey 用户脚本

    起因 一直以来,我都是直接在浏览器 Tampermonkey 扩展页面直接新建用户脚本来开发的: 对于一些简单的脚本,这没有什么问题,即改即看.但当代码多了以后问题就来了,自带编辑器开发体验确实不太舒 ...

  3. Vite ❤ Electron——基于Vite搭建Electron+Vue3的开发环境【一】

    背景 目前社区两大Vue+Electron的脚手架:electron-vue和vue-cli-plugin-electron-builder, 都有这样那样的问题,且都还不支持Vue3,然而Vue3已 ...

  4. 后台使用Spring MVC 4.15 版本 通过 ajaxFileUpload plugin插件上传文件相应时引起的一个小问题,Chrome、Firefox中出现SyntaxError:unexpected token <

    html: 使用ajaxFileUpload插件做文件上传时,后台返回json格式的数据,js代码如下: 接下来,把结果错误信息打印出来: 先在网上找了下解决办法方案,stackoverflow上有说 ...

  5. Jenkins使用Publish Over FTP Plugin插件上传FTP详解

    一.安装插件[Publish Over FTP] 二.在[系统管理]->[系统设置]->[Publish over FTP]->点击[增加]按钮,增加一个要连接的FTP: FTP S ...

  6. [Plugin] 文件上传利器SWFUpload使用指南

    SWFUpload是 一个flash和js相结合而成的文件上传插件,其功能非常强大.以前在项目中用过几次,但它的配置参数太多了,用过后就忘记怎么用了,到以后要用时又得 到官网上看它的文档,真是太烦了. ...

  7. Mac IntelliJ IDEA插件开发,IDEA Plugin SDK路径

    On Mac, select application icon in /Applications/ 官方文档: Setting Up a Development Environment

  8. 使用 vite 构建一个表情选择插件

    初始化 Vite 基于原生 ES 模块提供了丰富的内建功能,开箱即用.同时,插件足够简单,它不需要任何运行时依赖,只需要安装 vite (用于开发与构建)和 sass (用于开发环境编译 .scss ...

  9. vue2+vite初体验

    前言 自从 vite 发布之后,社区赞誉无数,而我也一直心水 vite 的轻量快速的热重载的特性,特别是公司的项目巨大,已经严重拖慢了热重载的速度了,每次热重载都要等上一小会,所以急需寻找一个解决方案 ...

随机推荐

  1. 数据结构解析-HashMap

    概要 HashMap在JDK1.8之前的实现方式 数组+链表,但是在JDK1.8后对HashMap进行了底层优化,改为了由 数组+链表+红黑树实现,主要的目的是提高查找效率. 如图所示: JDK版本 ...

  2. 【java虚拟机】类加载机制

    作者:平凡希 原文地址:https://www.cnblogs.com/xiaoxi/p/6959615.html 一.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中, ...

  3. 关于Ubuntu18.04 linux系统使用搜狗输入法 出现乱码

    解决: 执行下面的命令即可!无需重启系统 killall fcitx

  4. 【GIS】点图层符号的方向和大小

    方向:根据属性字段设置点图层中每个要素的符号方向和大小, 1 所有要素使用同一种符号---简单渲染 在图层属性---符号系统---单一符号中进行设置,首先设置符号,在后面的[高级]选项按钮中分别设置[ ...

  5. vmware 配置不同网段双网卡。

    一.前言 需求:由于LVS演练需要,需要配置两张linux OS网卡,而且是不同网段. 准备: 物理机:单网卡 VMware:centos 6.8 二.配置 第一步:新建虚拟机VMware,cento ...

  6. CentOS7系统搭建FTP服务器

    创建FTP服务器1.安装FTP服务 yum install -y vsftpd 默认的FTP服务的配置文件路径为/etc/vsftpd cd /etc/vsftpd[root@test924 vsft ...

  7. linux系统配置本地yum源

    1. 前言 学习Linux系统需要大量的实验,而每次安装系统和准备安装系统后的基础配置比较耗时费力.如果在生产环境中,遇到内网(无法访问互联网)情况下,就需要利用挂载的ISO文件内的Packages中 ...

  8. shell脚本测试变量是否为空,测试文件是否存在,sed修改配置文件参数,分支语句

    Shell脚本 1. 基本的几个变量 使用$?获取最近一次的执行结果: 使用$#获取传递的参数个数,类似C语言中的int argc; 使用$@获取所有的传参,类似C语言的char **argv 2. ...

  9. .Net性能调优-ArrayPool

    定义 高性能托管数组缓冲池,可重复使用,用租用空间的方式代替重新分配数组空间的行为 好处 可以在频繁创建和销毁数组的情况下提高性能,减少垃圾回收器的压力 使用 获取缓冲池实例:Create/Share ...

  10. 任由文字肆意流淌,更自由的开源 Markdown 编辑器

    对于创作平台来说内容编辑器是十分重要的功能,强大的编辑器可以让创作者专注于创作"笔"下生花.而最好取悦程序员创作者的方法之一就是支持 Markdown 写作,因为大多数程序员都是用 ...