为了让线上代码可追溯, 我开发了这个vite插件

6,775 阅读4分钟

人生的第一个vite插件

前言

想在控制台输出一下前端代码的一些构建信息, 比如打包时间、打包的人, 代码分支、commit是那个,方便在控制台追溯。

感兴趣的可以我9月写的这篇 juejin.cn/post/714051…, 当时把这段逻辑集成到了代码了里。

后来同事的其他项目觉得这个不错,也准备整一个,那总不能复制一份?

于是我想开发一个vite的插件让同事们可以直接引用。

这是我写的第一个vite插件大佬们嘴下留情

背景

遇到的问题

1、场景一

前端多人协同开发的情况下,比方测试站, 你发的代码, 貌似被人覆盖了,测试说不对啊, 你很烦, 这时你问: 谁发过吗, 没人说话, 倘若控制台可以追溯 谁 在几点 发布了什么 commit信息等等...那就不用迷茫了

2、打印出来可以帮助排查问题

开发说: 代码发了, 客户说: 我这边还是不行。

开发说: 刷新试试, 客户说: 我都刷了好几次了还是不行。

开发陷入了沉思

这是经常会有的对话

倘若控制台有打包信息,倘若控制台可以追溯 谁 在几点 发布了什么 commit信息等等...那就可以确定代码是发成功了

插件介绍

vite-plugin-aliyun-flow 流水线打印构建信息插件, 可以准确的在前端控制台看到当前运行代码的构建人、构建时间、分支、最新的COMMIT信息等, 方便追溯线上代码。

插件效果 image.png

使用

阿里云效流水线flow

这个插件仅限阿里云效流水线使用

安装

www.npmjs.com/package/vit…

npm i vite-plugin-aliyun-flow --D

在vite.config.js/ts中配置

import vitePluginAliFlow from "vite-plugin-aliyun-flow";

// plugins
plugins: [
    // 这里只需配置项目名称即可,其他信息都会从流水线自动抓取
    vitePluginAliFlow({ projectName: '绩效'}),
    ...
]

插件参数

目前版本只有一个项目名称配置

interface options {
    projectName?: string; // 项目名称 没有配置的话会取 package.json里的name字段
}

实现思路

确定输出的信息列表

1、打包时间 buildTime

我的思路是vite插件执行的时候获取当前时间就可以, 就是打包时间。

2、构建时nodejs的版本

这个我们用的是阿里云流水线, 我在想应该可以在流水线的运行时,全局变量获取到。

3、分支信息

同上

4、commit信息

同上

5、流水线执行人

同上

从流水线运行时, 获取环境变量里用的到的数据

1、打印一下 process.env 查看有哪儿些信息

信息量有点大呀

image.png

或者查看阿里云文档也可以 help.aliyun.com/document_de…

2、 找寻我们需要的子段

CI_RUNTIME_VERSION // 构建时nodejs的版本
EXECUTOR_NAME // 流水线执行人
CI_COMMIT_REF_NAME // 分支名
CI_COMMIT_TITLE // commit信息中文
CI_COMMIT_ID // commit哈希

写vite插件

vite插件文档 cn.vitejs.dev/guide/api-p…

我这个用一句话概括就是在打包的时候拿到了我要的信息,然后组装成了js字符串,插到了index.htmlscript标签里,运行中的时候可以执行就行了。

1、代码中获取流水线环境变量

process.env 为什么可以获取,因为打包的时候是用nodejs打包, process.env就是获取执行时环境变量的

const env = process.env

2、创建输出的js文件

这边单独写了个js文件, 写这些个输出

内容如下, 并且通过style给console加了颜色 背景 字体大小

最后通过插件读取这个js字符串, 和变量拼在一起。

// 1. 将css样式内容放入数
const styles = [
    'color: white',
    'background: green',
    'font-size: 19px',
    'border: 1px solid #fff',
    'text-shadow: 2px 2px black',
    'padding: 5px',
].join(';');

console.log(`%c${__APP_INFO__.projectName}, 当前版本: V${__APP_INFO__.pkg.version}`, styles);

console.log(
    `%c打包时间: ${__APP_INFO__.lastBuildTime}`,
    styles,
);
console.log(__GLOBAL_ENV_, __GLOBAL_ENV_);

console.log(`%c构建Node.js版本: ${__GLOBAL_ENV_.CI_RUNTIME_VERSION || '-'}`, styles);

console.log(`%c流水线执行人: ${__GLOBAL_ENV_.EXECUTOR_NAME || '-'}`, styles);

console.log(`%c分支: ${__GLOBAL_ENV_.CI_COMMIT_REF_NAME || '-'}`, styles);
console.log(
    `%cCOMMIT信息: ${__GLOBAL_ENV_.CI_COMMIT_TITLE || '-'} ${
        __GLOBAL_ENV_.CI_COMMIT_ID || '-'
    }`,
    styles,
);

3、拿到需要的信息, 拼接js字符串

extStr 就是上一步的js字符串

而后通过 htmlStr__APP_INFO____GLOBAL_ENV_ (这两是咱们要的信息)和 extStr 组装了起来。

// 获取环境变量
const env = process.env
// 获取当前项目包信息
const pkg: any = fs.readFileSync(process.cwd() + '/package.json', 'utf-8')
// 获取输出的js文件
const extStr: string = fs.readFileSync(path.join(__dirname, '../src/external.js'), 'utf-8')

const { name, version } = JSON.parse(pkg);
// 项目名称、 版本号、打包时间
const __APP_INFO__ = {
    projectName: options.projectName || name,
    pkg: { name, version },
    lastBuildTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
};
// 把输出的变量一起拼接js字符串
const HtmlStr: string = `const __GLOBAL_ENV_ = ${JSON.stringify(env)};
const __APP_INFO__ = ${JSON.stringify(__APP_INFO__)};
\n ${extStr}`

4、输出到index.html的body下面

transformIndexHtml vite暴露的方法,可以修改输出的index.html

如下就是 把HtmlStr放在script标签里输出到html的body下


transformIndexHtml(html): HtmlTagDescriptor[] {
    return [
        {
            tag: 'script',
            attrs: { defer: true },
            children: HtmlStr,
            injectTo: 'body'
        },
    ]
}

完整代码

import type { Plugin, HtmlTagDescriptor } from 'vite';
import dayjs from 'dayjs';
import path from 'path';
import fs from 'fs';

interface AliflowOptions {
    projectName?: string
}

export default function Aliflow(options: AliflowOptions): Plugin {
    // 流水线环境变量
    const env = process.env
    // 当前项目包信息
    const pkg: any = fs.readFileSync(process.cwd() + '/package.json', 'utf-8')
    // 输出的js
    const extStr: string = fs.readFileSync(path.join(__dirname, '../src/external.js'), 'utf-8')

    const { name, version } = JSON.parse(pkg);
    // 项目名称、包版本、打包时间等
    const __APP_INFO__ = {
        projectName: options.projectName || name,
        pkg: { name, version },
        lastBuildTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
    };
    // 拼接输出的js字符串 最后查到script标签里
    const HtmlStr: string = `const __GLOBAL_ENV_ = ${JSON.stringify(env)};
    const __APP_INFO__ = ${JSON.stringify(__APP_INFO__)};
    \n ${extStr}`

    return {
        name: 'vite-plugin-aliuyun-flow',
        apply: 'build',
        transformIndexHtml(html): HtmlTagDescriptor[] {
            // 将htmlStr插到body里
            return [
                {
                    tag: 'script',
                    attrs: { defer: true },
                    children: HtmlStr,
                    injectTo: 'body'
                },
            ]
        }

    };
}

代码

已经开源至github github仓库地址 github.com/zhangbowy/v…

总结

以上我们通过写vite插件注入打包信息, 让线上项目控制台可以追溯构建信息, 更好的排查问题。

后续考虑整合支持主流流水线, gitlab CI、jenkins、阿里云效流水线