我們經常使用元件,二次封裝或創造元件,在團隊內部使用; 可當我們想通過npm分享元件時,卻沒了之前的得心應手,本文旨在幫助大家在可以更輕鬆地釋出元件
首先,把vue元件釋出到npm這件事可以拆分成兩個部分:
在npm上釋出一個包
將vue元件打包
npm發包
有人說,發包不是一行命令就搞定了麼
npm publish複製程式碼
是的,可是還忽略了以下幾點:
首先你要在npmjs上註冊一個賬號
檢視你的
.npmrc
設定,確保你的registry是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 my-awesome-package@1.0.0
時,其實是相當於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開源:github.com/FEMessage/v…
說明
我們以開源元件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 元素名稱都是單個單詞的
我們選擇使用kebab-case
好例子:
components/
|- my-component.vue複製程式碼
好例子:
<!-- template -->
<my-component></my-component>複製程式碼
這裡我們選擇使用PascalCase
, 因為在程式語言裡,kebab-case
並不是最佳實踐。 也即,在非程式語言的範圍,我們能用kebab-case
就用
好例子:
Vue.component('MyComponent', {
// ...
})
import MyComponent from './my-component.vue'
export default {
name: 'MyComponent',
// ...
}複製程式碼
綜上所述,就可以明白前文中el-data-table的檔案命名風格為kebab-case
的原因了
更多文章請檢視我的部落格