如何從零編寫一個vite外掛 建立 vite 外掛通用模板

cyclonel發表於2024-08-19
  1. 初始化

mkdir vite-progress && cd vite-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/",
"
.d.ts"
],
"exclude": [
"node_modules",
"examples",
"dist"
]
}
1.4 安裝 vite

pnpm intsall vite --save-dev

  1. 配置 eslint 和 prettier(可選)
    安裝 eslint

pnpm i eslint @typescript-eslint / parser @typescript-eslint / eslint - plugin--save - dev
配置.eslintrc:

{
"root": true,
"env": {
"browser": true,
"es2021": true,
"es6": true,
"node": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module"
},
"plugins": ["@typescript-eslint"],
"rules": {
"no-console": 1,
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/no-explicit-any": "off"
}
}
配置格式化檔案
安裝 prettier (可選)

pnpm i prettier eslint - config - prettier eslint - plugin - prettier--save - dev
配置.prettierrc :

{
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"quoteProps": "as-needed",
"trailingComma": "all",
"bracketSpacing": true,
"arrowParens": "always",
"requirePragma": false,
"insertPragma": false,
"proseWrap": "preserve",
"endOfLine": "auto"
}
3. 新增 src / index.ts 入口

import type { PluginOption } from 'vite';

export default function vitePluginTemplate (): PluginOption {
return {
// 外掛名稱
name: 'vite-plugin',
// pre 會較於 post 先執行
enforce: 'pre', // post
// 指明它們僅在 'build' 或 'serve' 模式時呼叫
apply: 'build', // apply 亦可以是一個函式
config (config, { command }) {
console.log('這裡是config鉤子');
},

    configResolved (resolvedConfig) {
        console.log('這裡是configResolved鉤子');
    },

    configureServer (server) {
        console.log('這裡是configureServer鉤子');
    },

    transformIndexHtml (html) {
        console.log('這裡是transformIndexHtml鉤子');
    },
}

}
到這裡,那麼我們的基本模版就建好了,怎麼執行呢?

在當前目錄下執行

pnpm create vite my-vue-app --template vue

cd my-vue-app

pnpm i

修改 my-vue-app/package.json

{
"name": "my-vue-app",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"vue": "^3.2.37"
},
"devDependencies": {
"@vitejs/plugin-vue": "^3.1.0",
"vite": "link:../node_modules/vite"
}
}

主要是加入 "devDependencies": { "vite": "link:../node_modules/vite" }

這裡是讓 裡面和外面的 vite一個版本

然後修改 my-vue-app/vite.config.ts 檔案

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

import acnBuildPlugin from '../dist/index.mjs'

export default defineConfig({
plugins: [vue(), acnBuildPlugin()]
})

好了,在外面(vite-progress 目錄下)我們再下載個tsup ,tsup 是一個輕小且無需配置的,由 esbuild 支援的構建工具;

修改一下 vite-progress/package.json 的打包命令,及路徑

"main": "./dist/index.mjs", "scripts": { "test": "echo "Error: no test specified" && exit 1", "dev": "pnpm run build -- --watch --ignore-watch my-vue-app", "build": "tsup src/index.ts --dts --format cjs,esm", "build:vite": "pnpm run build && cd my-vue-app && pnpm run build", "prepublish": "pnpm run build", "release": "npx bumpp --push --tag --commit && pnpm publish" },

開發環境執行
開發環境執行:實時監聽檔案修改後重新打包(熱更新) pnpm run build:vite

到這裡你就可以 邊開發邊執行了 😄

vite 的外掛鉤子

  1. vite 獨有的鉤子
    enforce :值可以是pre 或 post , pre 會較於 post 先執行; apply :值可以是 build 或 serve 亦可以是一個函式,指明它們僅在 build 或 serve 模式時呼叫; config(config, env) :可以在 vite 被解析之前修改 vite 的相關配置。鉤子接收原始使用者配置 config 和一個描述配置環境的變數env; configResolved(resolvedConfig) :在解析 vite 配置後呼叫。使用這個鉤子讀取和儲存最終解析的配置。當外掛需要根據執行的命令做一些不同的事情時,它很有用。 configureServer(server) :主要用來配置開發伺服器,為 dev-server (connect 應用程式) 新增自定義的中介軟體; transformIndexHtml(html) :轉換 index.html 的專用鉤子。鉤子接收當前的 HTML 字串和轉換上下文; handleHotUpdate(ctx):執行自定義HMR更新,可以透過ws往客戶端傳送自定義的事件;

  2. vite 與 rollup 的通用鉤子之構建階段
    options(options) :在伺服器啟動時被呼叫:獲取、操縱Rollup選項,嚴格意義上來講,它執行於屬於構建階段之前; buildStart(options):在每次開始構建時呼叫; resolveId(source, importer, options):在每個傳入模組請求時被呼叫,建立自定義確認函式,可以用來定位第三方依賴; load(id):在每個傳入模組請求時被呼叫,可以自定義載入器,可用來返回自定義的內容; transform(code, id):在每個傳入模組請求時被呼叫,主要是用來轉換單個模組; buildEnd():在構建階段結束後被呼叫,此處構建結束只是代表所有模組轉義完成;

  3. vite 與 rollup 的通用鉤子之輸出階段
    outputOptions(options):接受輸出引數; renderStart(outputOptions, inputOptions):每次 bundle.generate 和 bundle.write 呼叫時都會被觸發; augmentChunkHash(chunkInfo):用來給 chunk 增加 hash; renderChunk(code, chunk, options):轉譯單個的chunk時觸發。rollup 輸出每一個chunk檔案的時候都會呼叫; generateBundle(options, bundle, isWrite):在呼叫 bundle.write 之前立即觸發這個 hook; writeBundle(options, bundle):在呼叫 bundle.write後,所有的chunk都寫入檔案後,最後會呼叫一次 writeBundle; closeBundle():在伺服器關閉時被呼叫

相關文章