前言
大家好,我是易师傅,在上一篇给大家带来了《如何入门去写一个 vite 插件》,能看的出来同学们也甚是喜欢,如果大家对 vite 感兴趣,可以关注我的专栏《vite 从入门到精通》;
因为公司目前大部分项目都已转为 vite,为了给社区添加一份贡献,故开发了一个已经应用到项目中的vite 前端打包进度条
的插件 vite-plugin-progress;
介绍
vite-plugin-progress 插件是一个在打包时展示进度条的插件,如果您觉得该插件对您的项目有帮助,欢迎 star ⭐️ 支持一下,感谢!
用法
- 安装
# npm
npm i vite-plugin-progress -D
# yarn
yarn add vite-plugin-progress -D
# pnpm
pnpm i vite-plugin-progress -D
- 使用(不带参数):在
vite.config.js / vite.config.ts
中配置
import progress from 'vite-plugin-progress'
export default {
plugins: [
progress()
]
}
- 参数 0ptions:
format
:自定义进度条的格式;width
:进度条在终端中的宽度;complete
:完成后的默认字符\u2588
;incomplete
:未完成的默认字符\u2591
;renderThrottle
:间隔更新时间默认16(毫秒);clear
:完成后是否清除终端,默认 false;callback
:完成后执行的回调函数;stream
终端中的输出格式流,默认stderr
;head
:进度条的头字符;
- 参数 options 中的
format
中各个标记含义:
:bar
:代表进度条;:current
:当前执行到哪的刻度;:total
:总刻度;:elapsed
:所用时间(秒);:percent
:完成的百分比;:eta
:预计完成时间(秒);:rate
:每一秒的速率;
- 使用(带参数):
// vite.config.js / vite.config.ts
import progress from 'vite-plugin-progress'
export default {
plugins: [
progress({
format: 'building [:bar] :percent',
total: 200,
width: 60,
complete: '=',
incomplete: '',
})
]
}
-
给自定义进度条加点颜色:
安装
picocolors
:pnpm i picocolors -D
使用:
// vite.config.js / vite.config.ts import progress from 'vite-plugin-progress' import colors from 'picocolors' export default { plugins: [ progress({ format: `${colors.green(colors.bold('Bouilding'))} ${colors.cyan('[:bar]')} :percent` }) ] }
如果您只想使用该插件的话,那么现在就去安装使用吧!
如果您对实现思路感兴趣的话,那么您可以继续向下滚动查阅哟 ~
实现思路
其实实现这个功能,我们最主要的考虑就是当前 vite 打包的进度到哪里了,那么我们思考两个问题:
- 考量当前 vite 打包的进度是到哪里了?
- 如何知道当前打包的进度?
熟悉 webpack
的朋友,肯定对 webpack 的打包进度条也不陌生;会发现在 webpack 中,webpack 暴露了一个 webpack.ProgressPlugin
的事件钩子,这样就导致在 webpack 中实现进度条会很容易,直接通过该钩子去封装即可;
但是在 vite 中由于是基于 Rollup
来构建打包代码,所以我们是没法知道当前 vite 打包进度的;
借用 vite 其中某位作者的原话:
简单理解意思就是说在 vite 打包时,是没法知道进度条的 0%-100%,因为您必须先确定要构建的模块的总数
虽然我们不知道模块总数,但是我们可以在第一次打包时模拟一个;
并且在第一次打包的时候,我们 记录下对应的模块数量
,然后 缓存起来
,这样我们不就可以知道对应的模块数量了吗?
说干就干 ~
第一次打包(模拟模块总数)
因为我们可以知道 src 目录
下所有的文件总数,所以就可以假设在第一次打包时用该总数来代替模块总数;
那么简单公式:进度条百分比 = 当前转换的模块 / 模拟的模块总数
import type { PluginOption } from 'vite';
import rd from 'rd';
export default function viteProgressBar(options?: PluginOptions): PluginOption {
// 文件类型总数
let fileCount = 0
let transformCount = 0
let transformed = 0 // 当前已转换的数量
retun {
...
config(config, { command }) {
if (command === 'build') {
const readDir = rd.readSync('src');
const reg = /\.(vue|ts|js|jsx|tsx|css|scss||sass|styl|less)$/gi;
readDir.forEach((item) => reg.test(item) && fileCount++);
}
},
transform(code, id) {
transformCount++
const reg = /node_modules/gi;
if (!reg.test(id){
percent = +(transformed / fileCount).toFixed(2)
}
}
}
}
与进度条配合
那么既然我们已经算出了基本的进度条,也知道了基本思路,那么我们就把进度条加进去
import type { PluginOption } from 'vite';
import progress from 'progress';
import rd from 'rd';
export default function viteProgressBar(options?: PluginOptions): PluginOption {
let fileCount = 0 // 文件类型总数
let transformCount = 0 // 转换的模块总数
let transformed = 0 // 当前已转换的数量
let lastPercent = 0; // 记录上一次进度条百分比
const bar: progress;
retun {
...
config(config, { command }) {
if (command === 'build') {
// 初始化进度条
options = {
width: 40,
complete: '\u2588',
incomplete: '\u2591',
...options
};
options.total = options?.total || 100;
const transforming = isExists ? `${colors.magenta('Transforms:')} :transformCur/:transformTotal | ` : ''
const chunks = isExists ? `${colors.magenta('Chunks:')} :chunkCur/:chunkTotal | ` : ''
const barText = `${colors.cyan(`[:bar]`)}`
const barFormat =
options.format ||
`${colors.green('Bouilding')} ${barText} :percent | ${transforming}${chunks}Time: :elapseds`
delete options.format;
bar = new progress(barFormat, options as ProgressBar.ProgressBarOptions);
// 统计目录下的文件总数
const readDir = rd.readSync('src');
const reg = /\.(vue|ts|js|jsx|tsx|css|scss||sass|styl|less)$/gi;
readDir.forEach((item) => reg.test(item) && fileCount++);
}
},
transform(code, id) {
transformCount++
const reg = /node_modules/gi;
if (!reg.test(id){
lastPercent = percent = +(transformed / fileCount).toFixed(2)
}
// 更新进度条
bar.update(lastPercent, {
transformTotal: cacheTransformCount,
transformCur: transformCount,
chunkTotal: cacheChunkCount,
chunkCur: 0,
})
},
closeBundle() {
// close progress
bar.update(1)
bar.terminate()
}
}
}
添加缓存
为了更准确的知道打包的进度,那么我们在第一次模拟了总数的时候,也要同时把真实的模块总数给缓存起来,这样在下一次打包时才能更加准确的计算出进度条;
新增缓存文件 cache.ts
import fs from 'fs';
import path from 'path';
const dirPath = path.join(process.cwd(), 'node_modules', '.progress');
const filePath = path.join(dirPath, 'index.json');
export interface ICacheData {
/** * 转换的模块总数 */
cacheTransformCount: number;
/** * chunk 的总数 */
cacheChunkCount: number
}
/** * 判断是否有缓存 * @return boolean */
export const isExists = fs.existsSync(filePath) || false;
/** * 获取缓存数据 * @returns ICacheData */
export const getCacheData = (): ICacheData => {
if (!isExists) return {
cacheTransformCount: 0,
cacheChunkCount: 0
};
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
};
/** * 设置缓存数据 * @returns */
export const setCacheData = (data: ICacheData) => {
!isExists && fs.mkdirSync(dirPath);
fs.writeFileSync(filePath, JSON.stringify(data));
};
使用缓存
// 缓存进度条计算
function runCachedData() {
if (transformCount === 1) {
stream.write('\n');
bar.tick({
transformTotal: cacheTransformCount,
transformCur: transformCount,
chunkTotal: cacheChunkCount,
chunkCur: 0,
})
}
transformed++
percent = lastPercent = +(transformed / (cacheTransformCount + cacheChunkCount)).toFixed(2)
}
实现架构图
最后
该系列会是一个持续更新系列,关于整个专栏 《Vite 从入门到精通》,我主要会从如下图几个方面讲解,请大家拭目以待吧!!!
宝贝们
,都看到这里了,要不点个赞呗 👍
今天的文章为了让vite打包更顺畅,我开发了这个vite插件分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/21685.html