在此之前,先做個定位,這不是一篇純粹的技術性文章,可以把它理解成一個敍述文章,記錄我開發插件的過程。
開始前簡單的吹個牛
vue2 也寫了很多年了,多人合作始終避不開用到別人的組件。關鍵是有些組件沒有文檔看起來是真的費勁。props還可以直接通過組件看出來,emit,ref,slot代碼一多看起來就比較費勁了。也想過一些解決方案,比如每個組件寫一個 readme。這就有一個問題,時間太緊了,誰來給你寫 readme 哦,開玩笑。
所以如果有一個能夠自動解析 vue 組件的東西就好了。在網上搜索了一下,vue 自動生成文檔,還真的有這麼個東西vuese,基本滿足要求,但是有幾點不是很滿意。
- 不支持 vue3
- 每次生成文檔需要 run 一下命令,當然也可以用 nodemon 監聽。但就是覺得有點 low
- ui 不是很好看(這個有點雞蛋挑骨頭,也是後面開始自己造 vite 插件的原因)
總體來説 vuese 是一個很好的項目,我的插件裏面很多的思路都是參考(其實就是抄 😂)了 vuese,我列出他的不好的,只是單純的給自己找個理由造個輪子。。。
説了這麼多你可能已經猜到我要造一個什麼插件了,總結一下:
- 自動解析 vue,並且支持 vue3
- 支持熱更新,寫了代碼能立即看到實時預覽
- 好看的 ui,最好能夠讓別人一看到文檔就覺得我寫的代碼很 nb,先不説代碼好不好,就看文檔就要能唬住人 😄
那麼為什麼是 vite 插件南?
- 剛出來沒多久,相比於 webpack 輪子比較少
- 初步瞭解好像大多數輪子都是用 ts 寫的,所以蹭着機會,學一波 ts。
- vite 介紹比傳統快 10-100 倍,初步體驗確實比較快。不過這不是主要原因,主要的是他比較新呀,輪子少,我可以順勢蹭一波熱度,説不定火了,就漲工資了。👏👏👏
吹了牛,需求也明確了
一直以為做一個開源最難的不是開發,而是弄到一個好一點的需求。但是這個 vite 插件的開發,還真的有點麻煩,差點就推翻了我的想法。😏
剛一開始就遇到了一個問題
- 如何從 vue 文件中獲取到 props,slots?
在此之前沒有做過類似的項目,也沒有遇到過類似的問題,完全不知道如何下手。初步想法是用正則去匹配,仔細想了哈,感覺不是很靠譜,主要是因為我的正則不行。🤙🤙🤙
我想不到怎麼去實現,總有人知道怎麼做嘛,去瞅瞅vuese怎麼實現的。首先看哈 package.json 裏面用了那些插件,把不認識的插件全部搜一下,瞭解有些啥作用。最後發現了這麼幾個庫,可以將 js 代碼解析成 ast 語法樹,完美的解析 vue。
{
"dependencies": {
"@babel/parser": "^7.10.3",
"@babel/traverse": "^7.10.3",
"@babel/types": "^7.3.0",
"vue-template-compiler": "^2.6.11"
}
}
經常聽到 bable 這個東西,卻沒有深入瞭解過,沒想到 vue 是用 bable 解析出來的,看來還是不行呀
言歸正傳,一一列舉一下他們的作用
| 插件 | 作用 |
|---|---|
| @babel/parser | 通過 parse 方法將 script 解析成 ast 語法樹 |
| @babel/traverse | 遍歷 ast 語法樹,可以更新刪除節點 |
| @babel/types | 判斷當前這個節點是什麼類型的 |
| vue-template-compiler | 解析.vue 為 ast,vue3 用的是@vue/compiler-sfc |
在使用中勒,發現@vue/compiler-sfc 中暴露出了@bable/parse的 parse 方法,bableParse
// compiler-sfc.d.ts
import { parse as babelParse } from '@babel/parser';
...
export { babelParse }
同時還發現了一個好工具,可在線將 js 代碼轉換成 ast:astexplorer
搭建開發環境
解決了一個技術性難題後,就開始創建項目,搭建開發環境了。這裏就忽略體驗 vite demo 和插件 demo 了。
在awesome-vite,看了很多的插件源碼,總結了一下幾個特點
- 幾乎都有兩個項目,一個是插件源碼,一個是 example 實例,有些插件是 vue、react 等多個框架公用的還會有多個實例
- 開發環境為了快速打包環境,用的比較多的是 tsup、tsc 這兩個插件
- 因為是源碼是 ts 的需要打包成 js,所以 package.json 裏面都要 main,types 這兩個字段
基礎項目結構創建
既然有了這些特點,就可以創建項目,逐步搭建開發環境了
大概的目錄結構是這樣的
- pacakges/
- vue-docs # 插件源碼
- example # example
- packages.json
看到這個 packages,裏面還有多個模塊,首先想到的就是 lerna + yarn + workspaces,所以直接一把梭
yarn init -y
yarn add lerna -D
npx lerna init
npx lerna create vue-docs
npx lerna create @vue-docs/exampe # 本來應該是這樣的,但是example他是一個vite的vue項目,所以用vite來創建
yarn create vite
最後的目錄是這樣的
- .git
- pacakges/
- example # vite創建的vue項目
- ...
- vue-docs # 插件代碼
- ...
- lerna.json
- package.json
修改一下 package.json,結果如下
{
"name": "monorepo", // 參考了一下lerna的寫法
"version": "0.0.0", // 0.0.0
"main": "index.js",
"license": "MIT",
"devDependencies": {
"lerna": "^4.0.0"
},
// 新增的
"private": true,
"workspaces": ["packages/*"]
}
項目結構有了,接下來搞一搞vue-docs這個目錄
vue-docs 插件目錄的搭建
前面已經説了,大多數插件用的都是 ts,並且用到了 tsup/tsc 這兩個插件。所以就按照這個標準去搭建
先來安裝插件, 這裏就直接使用 tsup 了
yarn workspace vue-docs add typescript tsup @babel/preset-typescript @babel/preset-env -D
配置 bable.config.js
// babel.config.js
module.exports = {
presets: [
["@babel/preset-env", { targets: { node: "current" } }],
"@babel/preset-typescript",
],
};
在 lib 中新建一個 index.ts,測試一下
export function sum(a: number, b: number): number {
return a + b;
}
sum(1, 2);
npx tsup ./lib/index.ts
發現生成了一個 dist/index.js 文件
"use strict";
Object.defineProperty(exports, "__esModule", { value: true }); // lib/index.ts
function sum(a, b) {
return a + b;
}
sum(1, 2);
exports.sum = sum;
到這裏基本 vue-docs 的搭建也算完成了,最後把命令加載 package.json scripts中
{
"scripts": "tsup ./lib/index.ts"
}
到這裏,項目基本的雛形已經有了,接下來就是繼續完善開發環境。下一節在再見
最後再來推廣一波
- 倉庫鏈接: vite-plugin-vue-docs
- 在線體驗: 解析.vue 文件,自動生成文檔