广告
返回顶部
首页 > 资讯 > 前端开发 > JavaScript >手写vite插件教程示例
  • 630
分享到

手写vite插件教程示例

2024-04-02 19:04:59 630人浏览 独家记忆
摘要

目录前言1. 什么是 vite 插件2. 为什么要写 vite 插件创建  vite 插件通用模板1. 初始化2. 配置 eslint 和 prettier(可选)3. 新

前言

大家好,我是易师傅,在现如今 vite 工具快开始盛行之下,我们是不是可以去做一件有意义的事呢,比如写一个 vite 插件,你觉得怎么样?

刚好我们可以趁 vite 插件 生态还未很成熟阶段,做一个让自己顺心,让领导赏心,让社区开心的插件,与之携手共进。

如果大家对 vite 感兴趣可以去看看专栏: 《Vite 从入门到精通》

通过本文你可以学到

  • 如何创建一个 vite 插件模板
  • vite 插件的 各个钩子作用
  • vite 插件的 钩子执行顺序
  • 如何写一个自己的插件

1. 什么是 vite 插件

vite 其实就是一个由原生 ES Module 驱动的新型 WEB 开发前端构建工具。

vite 插件 就可以很好的扩展 vite 自身不能做到的事情,比如 文件图片的压缩、 对 commonjs 的支持、 打包进度条 等等。

2. 为什么要写 vite 插件

相信在座的每位同学,到现在对 webpack 的相关配置以及常用插件都了如指掌了吧;

vite 作为一个新型的前端构建工具,它还很年轻,也有很多扩展性,那么为什么我们不趁现在与它一起携手前进呢?做一些于你于我于大家更有意义的事呢?

要想写一个插件,那必须从创建一个项目开始,下面的 vite 插件通用模板 大家以后写插件可以直接clone使用;

插件通用模板 GitHub:体验入口

插件 github:体验入口

建议包管理器使用优先级:pnpm > yarn > npm > cnpm

长话短说,直接开干 ~

创建  vite 插件通用模板

1. 初始化

1.1 创建一个文件夹并且初始化:初始化按照提示操作即可

mkdir vite-plugin-progress && cd vite-plugin-progress && pnpm init 

1.2 安装 typescript

pnpm i typescript @types/node -D

1.3 配置 tsconfig.JSON

{
  "compilerOptions": {
    "module": "ESNext",
    "target": "esnext",
    "moduleResolution": "node",
    "strict": true,
    "declaration": true,
    "noUnusedLocals": true,
    "esModuleInterop": true,
    "outDir": "dist",
    "lib": ["ESNext"],
    "sourceMap": false,
    "noEmitOnError": true,
    "noImplicitAny": false
  },
  "include": [
    "src
        total?: number;
        
        fORMat?: string;
    }
>;
export default function viteProgressBar(options?: PluginOptions): PluginOption {
    const { cacheTransformCount, cacheChunkCount } = getCacheData()
    let bar: progress;
    const stream = options?.stream || process.stderr;
    let outDir: string;
    let transformCount = 0
    let chunkCount = 0
    let transformed = 0
    let fileCount = 0
    let lastPercent = 0
    let percent = 0
    return {
        name: 'vite-plugin-progress',
        enforce: 'pre',
        apply: 'build',
        config(config, { command }) {
            if (command === 'build') {
                config.logLevel = 'silent';
                outDir = config.build?.outDir || 'dist';
                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);
                // not cache: Loop files in src directory
                if (!isExists) {
                    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++
            // not cache
            if(!isExists) {
                const reg = /node_modules/gi;
                if (!reg.test(id) && percent < 0.25) {
                    transformed++
                    percent = +(transformed / (fileCount * 2)).toFixed(2)
                    percent < 0.8 && (lastPercent = percent)
                  }
                if (percent >= 0.25 && lastPercent <= 0.65) {
                    lastPercent = +(lastPercent + 0.001).toFixed(4)
                } 
            }
            // Go cache
            if (isExists) runCachedData()
            bar.update(lastPercent, {
                transformTotal: cacheTransformCount,
                transformCur: transformCount,
                chunkTotal: cacheChunkCount,
                chunkCur: 0,
            })
            return {
                code,
                map: null
            };
        },
        renderChunk() {
            chunkCount++
            if (lastPercent <= 0.95) 
                isExists ? runCachedData() : (lastPercent = +(lastPercent + 0.005).toFixed(4))
            bar.update(lastPercent, {
                transformTotal: cacheTransformCount,
                transformCur: transformCount,
                chunkTotal: cacheChunkCount,
                chunkCur: chunkCount,
            })
            return null
        },
        closeBundle() {
            // close progress
            bar.update(1)
            bar.terminate()
            // set cache data
            setCacheData({
                cacheTransformCount: transformCount,
                cacheChunkCount: chunkCount,
            })
            // out successful message
            stream.write(
                `${colors.cyan(colors.bold(`Build successful. Please see ${outDir} directory`))}`
            );
            stream.write('\n');
            stream.write('\n');
        }
    };
    
    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)
    }
}

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;
    
    cacheChunkCount: number
}

export const isExists = fs.existsSync(filePath) || false;

export const getCacheData = (): ICacheData =&gt; {
    if (!isExists) return {
        cacheTransformCount: 0,
        cacheChunkCount: 0
    };
    return JSON.parse(fs.readFileSync(filePath, 'utf8'));
};

export const setCacheData = (data: ICacheData) =&gt; {
    !isExists &amp;&amp; fs.mkdirSync(dirPath);
    fs.writeFileSync(filePath, JSON.stringify(data));
};

最后

该系列会是一个持续更新系列,关于整个《Vite 从入门到精通》专栏,我主要会从如下图几个方面讲解,请大家拭目以待吧!!!

以上就是手写vite插件教程示例的详细内容,更多关于vite插件教程的资料请关注编程网其它相关文章!

--结束END--

本文标题: 手写vite插件教程示例

本文链接: https://www.lsjlt.com/news/152308.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 手写vite插件教程示例
    目录前言1. 什么是 vite 插件2. 为什么要写 vite 插件创建  vite 插件通用模板1. 初始化2. 配置 eslint 和 prettier(可选)3. 新...
    99+
    2022-11-13
  • 怎么手写vite插件
    这篇文章主要讲解了“怎么手写vite插件”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么手写vite插件”吧!1. 什么是 vite 插件vite 其实就是一个由原生 ES Mo...
    99+
    2023-07-02
  • vite插件打包更顺畅使用技巧示例
    目录前言介绍用法使用(带参数):给自定义进度条加点颜色:实现思路第一次打包(模拟模块总数)与进度条配合添加缓存使用缓存实现架构图最后前言 在上一篇给大家带来了《如何入门去写一个 vi...
    99+
    2022-11-13
  • Vite中使用Ant Design Vue3.x框架教程示例
    目录引言安装 ant-design-vuemain.js引入,全局使用按需引入引言 官网: https://www.antdv.com/docs/vue/introduce-cn 文...
    99+
    2022-11-13
  • iOS xcconfig编写示例教程
    目录引言注释include导入其他设置变量优先级(由高到低)引言 xcconfig文件的语法比较简单,每个配置文件都由一系列键值分配组成,这些键值分配具有以下语法: BUILD_SE...
    99+
    2022-11-13
  • React手写一个手风琴组件示例
    目录知识点结构分析AccordionItem子组件Accordion容器组件知识点 emotion语法react语法css语法typescript类型语法 结构分析 根据上图,我们来...
    99+
    2022-11-13
  • pytorch教程实现mnist手写数字识别代码示例
    目录1.构建网络2.编写训练代码3.编写测试代码4.指导程序train和test5.完整代码 1.构建网络 nn.Moudle是pytorch官方指定的编写Net模块,在init函数...
    99+
    2022-11-12
  • golang gorm开发架构及写插件示例
    目录1. 开发1.1. 架构1.2. 写插件1.2.1. 注册新的callback1.2.2. 删除现有的callback1.2.3. 替换现有的callback1.2.4. 注册c...
    99+
    2022-11-13
  • TypeScript手写一个简单的eslint插件实例
    目录引言前置知识第一个eslint规则:no-console本地测试本地查看效果no-console规则添加功能:排除用户指定的文件发布npm包引言 看到参考链接1以后,觉得用TS...
    99+
    2023-02-06
    TypeScript eslint插件 TypeScript eslint
  • vue时间组件DatePicker组件的手写示例
    概述 在日常工作中,比不可少会用到时间组件,我们的第一反应就是直接到组件库去找一下现成的来用下,毕竟,时间组件看起来还是很复杂的,对于没接触过的人来说,要自己去写一个这样的组件出来,...
    99+
    2022-11-13
  • 汇编基础程序编写教程示例
    目录源程序1.1 构成寄存器与段的关联假设标号定义一个段程序结束标记程序返回程序运行1.2 源程序中的“程序”1.3 段结束、程序结束、程序返回1.4 语法错误和逻辑错误2 程序执行...
    99+
    2022-11-12
  • 手写Vue内置组件component的实现示例
    目录前言内置组件component的使用component组件的原理分析虚拟DOM与原生DOMrender函数的使用尝试手写实现component总结最近在复习Vue的源码,今天带大...
    99+
    2022-11-13
  • Vue3编写自定义指令插件的示例代码
    编写自定义插件 // src/plugins/directive.ts import type { App } from 'vue' // 插件选项的类型 interface Opt...
    99+
    2022-11-13
  • 为Android Studio编写自定义Gradle插件的教程
    Google已经建议Android开发全部转向Android Studio开发,Android Studio 是使用gradle编译、打包的,那么问题来了,gradle可是有一...
    99+
    2022-06-06
    Android Studio studio gradle 教程 Android
  • C语言如何写类实现教程示例
    目录引言操空MYSQL的C程序定义个 联合体+结构体 类型 Parameter引言 以前用C++BUILDER  写类非常爽. 类把涉及数据相关的操作打...
    99+
    2023-05-17
    C语言如何写类 C语言
  • React大屏可视化脚手架教程示例
    目录使用 create-react-app 初始化引入 antd UI库使用 craco 插件来自定义配置自定义 antd 主题,使用 less 作为 css 预处理器修改 crac...
    99+
    2022-11-13
  • 小程序缓存插件的示例分析
    这篇文章主要为大家展示了“小程序缓存插件的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“小程序缓存插件的示例分析”这篇文章吧。背景wx.request是...
    99+
    2022-10-19
  • HDFS文件写流程的示例分析
    小编给大家分享一下HDFS文件写流程的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!图理解:详解HDFS写的过程:1.Client客户端发出请求open到...
    99+
    2023-06-03
  • 手写可拖动穿梭框组件CustormTransfervue实现示例
    目录本文内容最终效果图组件html布局穿梭框左侧内容穿梭框右侧内容穿梭框中间向左、向右按钮把排序好的穿梭数据传给父组件整体代码小结本文内容 需求是实现类似 el-transfer的组...
    99+
    2022-11-13
    vue拖动穿梭框CustormTransfer 手写 CustormTransfer
  • python编写第一个交互程序步骤示例教程
    Input()函数编写 1.编写一个稍微复杂一点的程序。使用Input()函数编写一个请用户输入名字的程序。 (1)打开IDLE开发环境,然后选择“File”...
    99+
    2022-11-13
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作