??vue組件發布npm最佳實踐
我們經常使用組件,二次封裝或創造組件,在團隊內部使用; 可當我們想通過npm分享組件時,卻沒了之前的得心應手,本文旨在幫助大家在可以更輕鬆地發布組件
首先,把vue組件發布到npm這件事可以拆分成兩個部分:
- 在npm上發布一個包
- 將vue組件打包
npm發包
有人說,發包不是一行命令就搞定了麼
npm publish
是的,可是還忽略了以下幾點:
- 首先你要在npmjs上註冊一個賬號
- 查看你的
.npmrc
設置,確保你的registry是https://www.npmjs.com/, 而不是淘寶源 - 在終端
npm login
,登錄你的賬號
做好以上三點,纔可以通過npm publish
簡單地發布一個包。若要遵循最佳實踐,還有一些準備工作要做好,下面將為你講述
完善基本信息
package.json的以下欄位需要注意
name
version
description
keywords
author
license
repository
main
unpkg
module
scripts
engines
name
就是發布到npm上的包名,也即別人安裝時輸入的名字yarn add ${name}
, 包名應該是kebab-case
, 即英文單詞全小寫,中劃線分割(lower case and dash-separated)
version
是語義化的,major.minor.patch
. 如果是major
變動,通常意味著不兼容的修改; 如果是minor
,意味著添加向後兼容的新功能,如果是patch
, 意味著bug的修復。詳情見semver.org
description
是對包的描述,在npmjs.com上搜索時會顯示,有助於用戶在搜索時進行篩選
keywords
同樣也是幫助用戶查找到你的包
author
的格式一般是${your name} ${email}
, 當然也可以是一個github地址
license
可能很多人會忽略,最好也寫上去。至於用哪個,vue的官方項目全是MIT,因此我也是MIT,不糾結
repository
的格式參考如下:
"repository": {
"type": "git",
"url": "https://github.com/FEMessage/el-data-table.git"
}
這樣在npm包頁面就有會個github的入口
main
定義了包的入口文件,在NodeJs環境,語句import pkg from package-name
時,其實導入的就是main
定義的文件,它可以是CommonJs格式的, 也可以是umd格式
需要注意的是,當你把一個包發布到npm上時,它同時也可以在unpkg上獲取到。也就是說,你的代碼既可能在NodeJs環境也可能瀏覽器環境執行。為此你需要用umd格式打包,並且在package.json定義unpkg
欄位,一般而言此時它的命名為name.min.js
最後,別忘了定義module
或jsnext:main
欄位,它表示用ES6模塊格式打包,給Webpack 2+或Rollup等先進的構建工具來處理。
我們來看一下三個欄位的示例:
"main": "dist/el-data-table.js",
"unpkg": "dist/el-data-table.min.js",
"module": "dist/el-data-table.esm.js"
scripts
為了防止出現發包前忘記構建的烏龍事件,定義一下發布前的腳本, 這樣每次執行npm publish
前都會先執行npm run build
"prepublishOnly": "npm run build"
engines
可以告訴用戶運行你的包對NodeJs版本的要求,這是非常重要的,不然你使用了NodeJs新版本特性,卻沒有定義該欄位,導致低版本NodeJs用戶運行報錯,讓人摸不著頭腦。
定義依賴
當你開發一個項目時,比如一個靜態網站或一個單面應用,dependencies和devDependencies並沒有太多區別,因為你npm install
或 yarn
時,這些依賴都會下載下來,因為你是在開發。
但對於發布到npm的包則不同:
dependencies 是運行你的包必須安裝的依賴,即當用戶yarn add my-awesome-package
時,這些依賴也會下載。
devDependencies 是開發你的包時需要安裝的依賴,比如eslint
, jest
等開發工具,當用戶yarn add my-awesome-package
時,這些依賴並不會下載!
peerDependencies 一般用於開發插件的場景,它要求用戶必須預先安裝了某些依賴。比如開發webpack
的插件,如果你把對webpack
的依賴定義成dependencies, 如果用戶安裝的webpack
跟dependencies裏的minor
版本不一致, 則用戶yarn add my-webpack-plugin
時會把dependencies定義的webpack
也下載下來,也即用戶會安裝兩個major
版本相同的webpack
, 這就不合適了。
所以說,定義好你的包的依賴,可以讓用戶安裝使用你的包時少點困惑,多些愉悅。
忽略文件
如果有 .gitignore
文件,則發布時會忽略 .gitignore
中定義的文件; 也即這些文件不需要在.npmignore
重新定義。如果用.gitignore
忽略了dist
目錄,但發包時又需要發布dist
目錄,此時可以在package.json定義files
欄位,這是一個白名單,裡面的文件都會被發布出去
"files": [
"dist"
]
需要注意的是,子文件夾.gitignore
或.npmignore
同樣有效,而它們會覆蓋files
欄位
另外,有些文件無論如何設置,都不會發布出去:
node_modules
.git
(包括.gitignore
)
README.md
別忘了這個文件,寫下與包相關的更具體的信息,告訴用戶這個包有哪些功能,如何使用。這很重要,用戶不會使用一個沒有文檔說明的包!
發布
一個版本只能發布一次,為了避免每次手動修改package.json
, 可以使用npm version [major | minor | patch]
命令來更新package.json
裏的版本
打標籤
假設你的包最新版本是1.0.0
, 當用戶yarn add my-awesome-package
或yarn add [email protected]
時,其實是相當於yarn add my-awesome-package@latest
, 即不指定標籤安裝時,默認安裝latest
版本。
假設你正在開發2.0.0
版本,它還不穩定,你想發布它讓用戶測試一波,此時又不能讓它變成latest
版本,不然用戶yarn add my-awesome-package
時就安裝了2.0.0
了,那將讓用戶崩潰。這時該怎麼辦呢?標籤就用上場了。
可以這樣發布
npm publish --tag beta
則用戶yarn add my-awesome-package
安裝的是1.0.0
版本, yarn add my-awesome-package@beta
時,安裝的是2.0.0
版本,不影響老用戶,棒!??
記住,你只能對一個版本打一個標籤,使用npm dist-tag ls
可以查看npm包一共打了幾個標籤
打包Vue
腳手架
經過一番折騰,在Vue Conf上找到一個vue組件的打包腳手架(vue官方文檔也有說明),進行「本土化」修改完善後,已在github開源:https://github.com/FEMessage/vue-sfc-cli
說明
我們以開源組件el-data-table為例,解釋目錄結構及文件
├── README.md
├── build
│ └── rollup.config.js
├── dist
│ ├── el-data-table.esm.js
│ ├── el-data-table.min.js
│ └── el-data-table.umd.js
├── docs
│ ├── build
│ └── index.html
├── package.json
├── src
│ ├── el-data-table.vue
│ └── index.js
├── styleguide.config.js
├── test
│ └── index.test.js
└── yarn.lock
先來看三個文件:
README.md
package.json
yarn.lock
README.md
與package.json
大家都懂,有yarn.lock
因為是我們鼓勵大家使用yarn, 它比npm
更快。雖然npm
6.0號稱提速17倍(可以想像6之前是得有多慢??),但經測試,還是不如yarn
接下來看build
, dist
, src
目錄
├── build
│ └── rollup.config.js
├── dist
│ ├── el-data-table.esm.js
│ ├── el-data-table.min.js
│ └── el-data-table.umd.js
├── src
│ ├── el-data-table.vue
│ └── index.js
build
目錄下放編譯時的配置文件,這個跟vue-cli 2.x
生成的模板build目錄作用是一樣的,只不過這裡放置的是rollup.config.js
。至於為什麼用Rollup, 一是因為配置更簡單,二是因為它更適合打包類庫,當源文件中有import lib from awesome-lib
類似的代碼時,Rollup並不會把awesome-lib
捆綁輸出,這正是開發類庫或組件需要的特性
dist
是輸出目錄,也有叫lib
的,我也糾結了好久。看了一些優秀的開源項目,發現叫dist
的比較多,而webpack4
默認的輸出目錄也是dist
, 因此決定用dist
。至於dist
目錄下會有三個文件,前文已說過原因。而命名為何不是camelcase
, 而是kebab-case
, 後面風格指南會說到
src
是輸入目錄。把index.js
放在src
目錄,也是經過一番考慮。也想把index.js
跟package.json
同級,最終參考了webpack4
, 它默認輸入是src/index.js
, 那就跟主流保持一致。該文件主要工作是把src
目錄下的vue文件設置成vue的插件。同樣,vue文件的命名後面風格指南會說到
├── test
│ └── index.test.js
test
目錄下是基於jest
及vue/test-utils
的單元測試文件,具體教程可參考官方文檔
├── docs
│ ├── build
│ └── index.html
├── styleguide.config.js
docs
存放的是組件的api文檔,包含props
, slot
, event
等內容的說明,使用的是vue-styleguidist作為vue組件文檔生成工具。為啥叫 docs
呢,因為Github Pages
支持從master
分支的docs
目錄讀取文件,在倉庫Settings
裏選擇Github Pages
的Source
即可, 具體看官方文檔
風格指南
vue組件把template/script/style都放在一個vue文件裏,這個稱之為單文件組件,Single File Component
,縮寫為SFC, 這就是vue-sfc-cli中sfc的寓意
通讀vue官方風格指南, 由於我們是kebab-case
的重度用戶,因此我們更看重的是在多個項目中保持相同的大小寫規則,以下是摘取的適用於我們團隊協作習慣的指南:
- 組件名,應該多個單詞
這樣做可以避免跟現有的以及未來的 HTML 元素相衝突,因為所有的 HTML 元素名稱都是單個單詞的
- 單文件組件的文件名應該要麼始終是單詞大寫開頭 (PascalCase),要麼始終是橫線連接 (kebab-case)
我們選擇使用kebab-case
好例子:
components/
|- my-component.vue
- 在 DOM 模板(template)中總是 kebab-case 的
好例子:
<!-- template -->
<my-component></my-component>
- JS/JSX 中的組件名應該始終是 PascalCase 的,儘管在較為簡單的應用中只使用Vue.component 進行全局組件註冊時,可以使用 kebab-case 字元串
這裡我們選擇使用PascalCase
, 因為在編程語言裏,kebab-case
並不是最佳實踐。 也即,在非編程語言的範圍,我們能用kebab-case
就用
好例子:
Vue.component(MyComponent, {
// ...
})
import MyComponent from ./my-component.vue
export default {
name: MyComponent,
// ...
}
綜上所述,就可以明白前文中el-data-table的文件命名風格為kebab-case
的原因了
參考
- How to publish your package on npm
- module-best-practices
- npm-style-guide
- semver.org
- unpkg
- umd
- npm scripts
- .npmignore
- 2018 Vue Conf
- Vue Cookbook
- Vue Style Guide
- npm-vs-yarn
- Github Pages
推薦閱讀: