<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          如何開發(fā)一個(gè) Vite 插件?以 vite-plugin-monitor 為例

          共 7873字,需瀏覽 16分鐘

           ·

          2021-10-15 00:55

          背景

          最近在webpack項(xiàng)目里接入了Vite(dev mode),為開發(fā)提效。效果是真的猛。

          項(xiàng)目啟動(dòng)速度提升70%-80%,HMR直接碾壓webpack dev server

          為了更加精準(zhǔn)的計(jì)算收益,就需要將Vite啟動(dòng)相關(guān)的指標(biāo)進(jìn)行上報(bào)(啟動(dòng)時(shí)間,HMR,頁(yè)面加載等等時(shí)間)

          為此就要通過開發(fā)插件收集這些信息,然后通過埋點(diǎn)上報(bào)sdk上報(bào)到數(shù)據(jù)分析的平臺(tái)

          遇到的問題

          通過查閱官方文檔[1]并未找到相關(guān)的鉤子直接獲取到這些指標(biāo)

          但在開發(fā)的時(shí)候添加 --debug就能很詳細(xì)的看到所有資源的處理時(shí)間,HMR,詳細(xì)的啟動(dòng)時(shí)間等等

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

          為此只能通過一些hack的手段獲取這些指標(biāo)了,下面將展開詳細(xì)的介紹

          期望

          通過向目標(biāo)工程引入插件,通過特定的回調(diào)函數(shù)即可獲取到debug模式下反饋的各種信息

          準(zhǔn)備工作

          比較詳細(xì)的介紹一下開發(fā)步驟

          初始化工程

          創(chuàng)建插件目錄

          mkdir vite-plugin-monitor

          cd vite-plugin-monitor

          初始化pkg.json

          npm init -y

          安裝必要依賴

          yarn add -D vite typescript @types/node rimraf

          添加必要的兩個(gè)指令dev,build,配置入口文件dist/index.js

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

          其中dev環(huán)境下添加了-w(--watch)參數(shù),當(dāng)文件有變動(dòng)時(shí),以便實(shí)時(shí)的進(jìn)行更新

          rimraf的作用是替代rm -rf指令,且是跨平臺(tái)的,windows下同樣生效

          插件使用typescript開發(fā),更有助于插件后續(xù)的維護(hù)

          其中build直接使用typescript提供的默認(rèn)tsc指令,對(duì)ts直接進(jìn)行轉(zhuǎn)換

          根目錄創(chuàng)建 tsconfig.json 內(nèi)容如下

          {
              "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 目錄下進(jìn)行開發(fā),里面存放我們的源碼

          目錄結(jié)構(gòu)

          最終目錄如下

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

          簡(jiǎn)單插件示例

          根據(jù)插件開發(fā)文檔,在src/index.ts文件下編寫如下簡(jiǎn)單的代碼;

          • name:標(biāo)識(shí)插件的名稱
          • apply:標(biāo)識(shí)插件在哪個(gè)時(shí)期工作(serve|build),默認(rèn)都會(huì)調(diào)用
          • config:這個(gè)鉤子接收原始用戶配置(命令行選項(xiàng)指定的會(huì)與配置文件合并)和一個(gè)描述配置環(huán)境的變量
          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)
                // 可以做進(jìn)一步的修改,會(huì)自動(dòng)合入當(dāng)前的配置
                // return
              },
            };
          }

          一個(gè)打印Vite配置的插件就搞定了,下面就是測(cè)試我們開發(fā)的插件

          本地測(cè)試插件

          首先是轉(zhuǎn)換我們的ts=> js ,執(zhí)行前面配置的指令yarn dev,就會(huì)看見生成了一個(gè)dist目錄,里面有轉(zhuǎn)換后的代碼

          接著執(zhí)行npm link在全局生成一個(gè)軟連接,指向當(dāng)前項(xiàng)目

          npm link

          在一個(gè)vite項(xiàng)目里的執(zhí)行npm link vite-plugin-monitor(monitor根據(jù)實(shí)際情況替換),向目標(biāo)項(xiàng)目加入此依賴

          npm link vite-plugin-monitor

          接著就可以在Vite項(xiàng)目的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()
            ]
          })

          接著通過配置的指令啟動(dòng)vite,就能看到我們插件的打印的配置文件內(nèi)容了

          圖片

          由于是通過軟連接的方式引入的插件,那么在插件工程里的任意更改都會(huì)實(shí)時(shí)生效,也就避免了頻繁的執(zhí)行yarn add file:localProjectDir

          功能開發(fā)

          有了前文的鋪墊內(nèi)容,下面就是功能開發(fā)

          獲取啟動(dòng)耗時(shí)

          項(xiàng)目啟動(dòng)后會(huì)在終端中輸出ready in xxms

          圖片

          為此咱們使用Vs Code在源碼[2]中搜一下這個(gè)關(guān)鍵字

          圖片

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

          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`)
          }

          這個(gè)performance.now()等同于Date.now()即當(dāng)前時(shí)間,通過global.__vite_start_time就能獲取到服務(wù)啟動(dòng)時(shí)間

          我們就從這個(gè)info方法入手,給它重定義一下,通過configureServer鉤子可以獲取到server實(shí)例

          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方法的調(diào)用
                server.config.logger.info = function _info(str{
                  // 調(diào)用原info方法
                  info.apply(thisarguments);
                  // 通過字符串內(nèi)容進(jìn)行一個(gè)簡(jiǎn)單的判斷
                  if (str.includes('ready in')) {
                    console.log('startupDuration'Date.now() - startTime)
                  }
                };
              },
            };
          }

          啟動(dòng)一個(gè)項(xiàng)目看看效果,成了。

          HMR時(shí)間獲取

          熱更新時(shí),終端中會(huì)出現(xiàn)下面的日志

          圖片

          同理源碼里搜一搜,能夠定位出如下內(nèi)容

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

          暫以打印這個(gè)日志的時(shí)間作為HMR開始的時(shí)間

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

          觸發(fā)HMR時(shí),客戶端會(huì)發(fā)出一個(gè)獲取資源的請(qǐng)求,請(qǐng)求攜帶了一個(gè)import參數(shù),我們通過這個(gè)參數(shù)來標(biāo)識(shí)這個(gè)特定的請(qǐng)求

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

          鉤子中的server實(shí)例包含middlewares屬性可以向上添加自定義的中間件處理方法

          • 通過URL實(shí)例解析search參數(shù),然后判斷是否包含import&
          • 重定義end方法,在資源傳回到客戶端后打印耗時(shí)
          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({
                // 在資源返回后打印耗時(shí)
                end.apply(thisarguments);
                console.log(Date.now() - startTime)
              };
            }
            next();
          });

          事實(shí)上通過--debug啟動(dòng)服務(wù),能看到在HMR時(shí)會(huì)打印4個(gè)時(shí)間

          圖片

          目前方法僅僅得到了vite:hmr部分的時(shí)間,與實(shí)際耗時(shí)還有一絲絲差異

          小結(jié)

          本篇主要介紹了monitor插件開發(fā)的背景,要解決的問題,目標(biāo)以及開發(fā)插件所需的一些列準(zhǔn)備工作

          功能開發(fā)介紹了啟動(dòng)時(shí)間與HMR時(shí)間的獲取方式

          更加詳細(xì)的信息目前看來只能通過--debug看到,下一步的計(jì)劃就是通過某種手段拿到debug下打印的日志內(nèi)容

          由于時(shí)間關(guān)系,這部分hack還沒完成。準(zhǔn)備假期抽時(shí)間實(shí)現(xiàn)一下。下一篇文章將詳細(xì)的介紹最終實(shí)現(xiàn)。

          • 倉(cāng)庫(kù)源碼[3]

          參考資料

          [1]

          官方文檔: https://vitejs.dev/guide/api-plugin.html

          [2]

          源碼: https://github1s.com/vitejs/vite

          [3]

          倉(cāng)庫(kù)源碼: https://github.com/ATQQ/vite-plugin-monitor


          瀏覽 260
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  黄色一级片欧美 | 国产一级婬乱A片免费 | 精品人伦一区二区三电影 - 百度 麻豆网站-麻豆午夜在线-成人AV | 老逼综合| 一区二区高清无码 |