vite插件-??

vite整合了rollup,所以vite的插件可以看成是受限制的rollup插件悲幅,它支持部分rollup的Hooks套鹅。vite也提供僅屬于它自己的Hooks。

命名規(guī)范

  • 插件希望在vite和rollup里使用: rollup-plugin-xxx
  • 僅在vite使用:vite-plugin-xxx

兼容rollup部分Hooks(僅列舉常用的)

服務啟動時

會兼容rollup的optionsbuildStart鉤子汰具,只會執(zhí)行一次卓鹿,文件改變觸發(fā)的打包不會再觸發(fā)鉤子與文件更新無關,也符合插件編碼規(guī)范留荔。

每個模塊

為了實現(xiàn)代碼編譯能力吟孙,兼容resolveIdload存谎、transform拔疚、buildEnd

  • resolveId:找到對應文件
  • load:加載文件的源碼
  • transform:把文件源碼轉換成目標代碼
  • buildEnd:代碼編譯完成

服務關閉時

會觸發(fā)closeBundle既荚。

在vite里使用rollup插件

如果需要在vite里使用rollup的插件,vite會用自己的規(guī)范讀取rollup插件的config栋艳,只會執(zhí)行vite里兼容的Hooks恰聘。

常見的場景是,已經(jīng)寫了rollup的插件,不想重寫一個插件來兼容vite了晴叨,有沒有辦法能使我們在vite按照rollup的規(guī)則來使用插件呢凿宾?
vite提供了rollupOptions配置項,使我們可以在build中配置rollup 插件:

// vite.config.js
import { defineConfig } from 'vite'

export default defineConfig({
  // ...
  build: {
    rollupOptions: {
      plugins: []
    }
  }
})

vite 在 build 的時候其實是執(zhí)行了 rollup 的 build兼蕊。
?? 需要注意的是modulePased鉤子不會被觸發(fā)初厚,vite為了對代碼整體進行ast的解析,在開發(fā)環(huán)境代碼編譯是通過esbuild進行孙技,在執(zhí)行完rollup插件會傳給esbuild來產(chǎn)出最終的代碼产禾,所以modulePased這部分會交給esbuild來完成。

總結:適合在vite使用的rollup插件需要滿足三要素

  • 沒有使用 moduleParsed 鉤子
  • 打包和輸出之間沒有很強的耦合
  • 代碼輸出不過分依賴Hooks的執(zhí)行或使用到的Hooks是vite所兼容的

vite專屬的Hooks

config

在config里返回的對象會被合并到vite的配置當中立即生效牵啦,可以根據(jù)vite當前配置(包含用戶自定義配置)自動生成額外的配置或初始化用戶漏傳的配置亚情,它的返回值有兩種方式,返回對象或Promise哈雏。

export default () => {
  return {
    name: 'test',
    config(userConfig) {
      // 方式1直接返回對象
      return {
        resolve: {
          alias: {
            '@diy': '/src/diy'
          }
        }
      }
      // 方式2在Promise里的resolve返回對象楞件,
      return new Promise(resolve => {
        resolve({
          resolve: {
            alias: {
              '@diy': '/src/diy'
            }
          }
        })
      })

    }
  }
}

configResolved

所有插件的config執(zhí)行完畢會觸發(fā)這個hook,可以在這個鉤子里拿到最終的配置裳瘪,在這個鉤子不能再修改配置了土浸。
可以將配置存到插件的運行環(huán)境(閉包)中,方便后續(xù)在其它鉤子中讀到它彭羹。

export default () => {
  let root = ''
  return {
    name: 'test',
    config(userConfig) {
      return { resolve: { alias: { '@diy': '/src/diy' } } 
    },
    configResolved(config) {
      root = config.root
      console.log(config.resolve)
      // { ...,  alias: [
      //    { find: /^\/@vite\//, replacement: [Function: replacement] },
      //    { find: '@diy', replacement: '/src/diy' }
      //  ]
      // } 
    }
  }
}

configureServer

在這個鉤子里可以獲取server的實例黄伊,增加devServer中間件做一些處理。

// server屬性
interface ViteDevServer {
  /**
   * 被解析的 Vite 配置對象
   */
  config: ResolvedConfig
  /**
   * 一個 connect 應用實例
   * - 可以用于將自定義中間件附加到開發(fā)服務器皆怕。
   * - 還可以用作自定義http服務器的處理函數(shù)毅舆。
      或作為中間件用于任何 connect 風格的 Node.js 框架。
   *
   * https://github.com/senchalabs/connect#use-middleware
   */
  middlewares: Connect.Server
  /**
   * 本機 node http 服務器實例
   */
  httpServer: http.Server | null
  /**
   * chokidar 監(jiān)聽器實例
   * https://github.com/paulmillr/chokidar#api
   */
  watcher: FSWatcher
  /**
   * web socket 服務器愈腾,帶有 `send(payload)` 方法憋活。
   */
  ws: WebSocketServer
  /**
   * Rollup 插件容器,可以針對給定文件運行插件鉤子虱黄。
   */
  pluginContainer: PluginContainer
  /**
   * 跟蹤導入關系悦即、url 到文件映射和 hmr 狀態(tài)的模塊圖。
   */
  moduleGraph: ModuleGraph
  /**
   * 以代碼方式解析橱乱、加載和轉換 url 并獲取結果
   * 而不需要通過 http 請求管道辜梳。
   */
  transformRequest(
    url: string,
    options?: TransformOptions
  ): Promise<TransformResult | null>
  /**
   * 應用 Vite 內(nèi)建 HTML 轉換和任意插件 HTML 轉換
   */
  transformIndexHtml(url: string, html: string): Promise<string>
  /**
   * 加載一個給定的 URL 作為 SSR 的實例化模塊
   */
  ssrLoadModule(
    url: string,
    options?: { isolated?: boolean }
  ): Promise<Record<string, any>>
  /**
   * 解決 ssr 錯誤堆棧信息
   */
  ssrFixStacktrace(e: Error): void
  /**
   * 啟動服務器
   */
  listen(port?: number, isRestart?: boolean): Promise<ViteDevServer>
  /**
   * 重啟服務器
   *
   * @param forceOptimize - 強制優(yōu)化器重新大伯啊,和命令行內(nèi)使用 --force 一致
   */
  restart(forceOptimize?: boolean): Promise<void>
  /**
   * 停止服務器
   */
  close(): Promise<void>
}

控制添加的中間件執(zhí)行順序:

export default () => {
  return {
    name: 'test',
    configureServer(server) {
      // 高優(yōu)先級:直接添加中間件優(yōu)先級很高泳叠,會在vite中間件執(zhí)行之前執(zhí)行 
      server.middlewares.use((req, res, next) => {
        next()
      })
      // 低優(yōu)先級:在Hook的返回值里添加作瞄,會在vite中間件執(zhí)行之后執(zhí)行
      return () => {
        server.middlewares.use((req, res, next) => {
          next()
        })
      }
    }
  }
}

中間件的入?yún)⒑蚭xpress中間件的入?yún)⒑x一樣。

?? 如果需要處理get請求的接口推薦使用高優(yōu)先級的方式危纫,vite的中間件會將頁面發(fā)出的get請求映射到index html里宗挥,輪不到低優(yōu)先級的中間件處理乌庶。

transformIndexHtml

處理入口html文件內(nèi)容的鉤子。

export default () => {
  return {
    name: 'test',
    transformIndexHtml(html) {
      console.log(html)
      /** 
       * 控制臺打印index.html文件的內(nèi)容:
       * <!DOCTYPE html>
       * <html lang="en">
       *   <head>
       *     <meta charset="UTF-8" />
       *     <link rel="icon" href="/favicon.ico" />
       *     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
       *     <title>Vite App</title>
       *   </head>
       *   <body>
       *     <div id="app"></div>
       *     <script type="module" src="/src/main.js"></script>
       *   </body>
       * </html>
       */
    }
  }
}

handleHotUpdate

熱更新的時候會觸發(fā)的鉤子契耿,鉤子能拿到熱更新模塊的信息瞒大。

export default () => {
  return {
    name: 'test',
    handleHotUpdate(ctx) {
      console.log(ctx)
      /**
       * {
       *    file: 更新的文件
       *    timestamp: 更新的時間
       *    modules: 更新的module [
       *      ModuleNode: modulePased處理的內(nèi)容
       *    ]
       *    ...
       * }
       */ 
    }
  }
}

熱更新后,通知客戶端處理熱更新:

export default () => {
  return {
    name: 'test',
    handleHotUpdate(ctx) {
      ctx.server.ws.send({
        type: 'custom',
        event: 'handleHotUpdate',
        data: {
          msg: 'hello client, hot updated',
          file: ctx.file,
          timestamp: ctx.timestamp
        }
      })
    }
  }
}

// app.jsx
if (import.meta.hot) {
  import.meta.hot.on('handleHotUpdate', val => {
    console.log(val)
  })
}

// 觸發(fā)熱更新搪桂,控制臺打印
/**
 * {
 *   msg: 'hello client, hot updated',
 *   file: '/.../src/App.jsx', (絕對路徑)
 *   timestamp: 1660728266941
 * }
 */

vite插件執(zhí)行時機

相對于rollup插件是按照配置數(shù)組順序執(zhí)行vite的執(zhí)行順序更加靈活透敌,按照數(shù)組執(zhí)行的前提下支持3階段配置。

  • pre
    首批被執(zhí)行的插件踢械,會在@rollup/plugin-alias插件執(zhí)行之后執(zhí)行酗电。

  • normal(默認值)
    第二批配執(zhí)行的插件,會在vite的build階段之前被執(zhí)行裸燎,可以根據(jù)配置判斷是否需要處理當前文件的代碼顾瞻。

  • post
    會在vite的build階段之后被執(zhí)行,進行代碼構建方面的工作(minimize德绿、代碼分析...)荷荤。

// vite-plugin-test.js
export default (enforce: 'pre' | 'post') => {
    return {
        name: 'test',
        enforce,
        buildStart() {
            console.log('buildStart:', enforce);
        }
    }
}

// vite.config.js
import { defineConfig } from 'vite'
import testPlugin from './plugins/test-plugin'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [testPlugin('post'), testPlugin(), testPlugin('pre')]
})

// 執(zhí)行vite
#sh: vite
/** 
 * 終端打印
 * buildStart: pre
 * buildStart: undefined
 * buildStart: post
 */

可以看到組件的執(zhí)行機制是先按照優(yōu)先級,再按順序移稳。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蕴纳,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子个粱,更是在濱河造成了極大的恐慌古毛,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件都许,死亡現(xiàn)場離奇詭異稻薇,居然都是意外死亡,警方通過查閱死者的電腦和手機胶征,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門塞椎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人睛低,你說我怎么就攤上這事案狠。” “怎么了钱雷?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵骂铁,是天一觀的道長。 經(jīng)常有香客問我罩抗,道長拉庵,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任套蒂,我火速辦了婚禮名段,結果婚禮上阱扬,老公的妹妹穿的比我還像新娘泣懊。我一直安慰自己伸辟,他們只是感情好,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布馍刮。 她就那樣靜靜地躺著信夫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪卡啰。 梳的紋絲不亂的頭發(fā)上静稻,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天,我揣著相機與錄音匈辱,去河邊找鬼振湾。 笑死,一個胖子當著我的面吹牛亡脸,可吹牛的內(nèi)容都是我干的押搪。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼浅碾,長吁一口氣:“原來是場噩夢啊……” “哼大州!你這毒婦竟也來了?” 一聲冷哼從身側響起垂谢,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤厦画,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后滥朱,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體根暑,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年徙邻,在試婚紗的時候發(fā)現(xiàn)自己被綠了排嫌。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡鹃栽,死狀恐怖躏率,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情民鼓,我是刑警寧澤薇芝,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站丰嘉,受9級特大地震影響夯到,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜饮亏,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一耍贾、第九天 我趴在偏房一處隱蔽的房頂上張望阅爽。 院中可真熱鬧,春花似錦荐开、人聲如沸付翁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽百侧。三九已至,卻和暖如春能扒,著一層夾襖步出監(jiān)牢的瞬間佣渴,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工初斑, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留辛润,地道東北人。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓见秤,卻偏偏與公主長得像砂竖,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子秦叛,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容