首先在npm官網進行註冊登陸javascript
運行npm init
,能夠經過命令行進行一些初始化的設置,若是想快速進行設置,能夠運行npm init -y
,會在項目的根目錄生成一個package.json的文件,具體包含哪些配置能夠參考官方文檔,下面介紹一些經常使用的配置。vue
name:npm包的名稱java
version:包的版本號node
description:對包的功能進行描述react
main:包的入口文件,默認是index.jswebpack
repository:代碼的託管信息,通常是github地址git
keywords:關鍵字信息,便於包的搜索github
author:做者web
license:開源協議,通常是MIT和ISCvue-cli
bugs:提bug的頁面,默認是github的issue頁面
homepage:項目的主頁
最好增長README.md,用來對項目進行簡單的說明,好比如何安裝使用,以及一些api的介紹和例子。
在代碼開發完成之後,在命令行進行npm登錄npm login
。
最後使用npm publish
對包進行發佈。
使用eslint,對JavaScript的書寫規範作必定的限制,能夠在一些經過配置的基礎上增長一些團隊本身的限制項。
使用stylelint對樣式文件作一些規範化的工做,也能夠根據團隊的須要作一些定製化。
使用.editorconfig來配置編輯器的規範,保證縮進和換行等的一致性。
SemVer的中文名稱是語義化版本控制規範。npm默認使用SemVer來進行模塊的版本控制。一個發佈到npm的包要嚴格遵照SemVer的版本規範,否則會發布失敗。
主版本號.次版本號.修訂號,能夠用x.y.z的寫法來簡單表示。
修訂號(patch):只有在作了向下兼容的修正時才能夠遞增,能夠理解爲bug fix版本
次版本號(minor):只有在新增了能夠向下兼容的新功能的時候,才能夠遞增,能夠理解爲feature版本。
主版本號(major):只有在新增了沒法向下兼容的API的時候,才能夠遞增。
當要進行大版本迭代的時候,或者增長一些核心的功能,但又不能保證新版本百分之百正常,這個時候就能夠發佈先行版本。SemVer規範中使用alpha、beta和rc來修飾先行版本。
alpha:內部版本
beta:公測版本
rc:Release candiate,正式版本的候選版本
先行版本的版本號可使用:1.0.0-alpha、1.0.0-beta.一、1.0.0- rc.一、1.0.0-0.3.7等。
進行版本號比較時,x、y、z依次比較
先行版本號的規則是rc > beta > alpha
1.0.0 < 2.0.0 < 2.1.0 < 2.1.1
1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0- rc.1 < 1.0.0複製代碼
更多內容能夠看SemVer
在項目中須要單測和對代碼規範的校驗,若是每次修改,都對項目的全部代碼進行校驗,會有性能和時間上的浪費;還有若是老項目沒有接入單測和代碼規範,那麼若是對全部的代碼都進行校驗的話,會致使錯誤太多沒法提交代碼。如今項目中已經使用的方案是husky & lint-staged。
husky在安裝的時候,會執行這個包的npm install這個script,對項目的Git鉤子進行重寫,咱們就能夠在git的鉤子函數中作一些代碼方面的校驗工做。lint-staged這個庫只會新加入暫存區的文件進行相關的操做,這樣就能夠優化觸發操做的文件範圍。
package.json
{
...
"scripts": {
"lint": "eslint --fix src/",
"lint:style": "stylelint --fix 'src/**/*.less'",
"test": "cross-env BABEL_ENV=test jest --colors --config .jest.js",
"pre-commit": "lint-staged"
},
"lint-staged": {
"ignore": [
"build/*",
"node_modules"
],
"linters": {
"src/*.js": [
"eslint --fix",
"git add"
],
"src/**/*.less": [
"stylelint --fix",
"git add"
],
"src/components/**/*.js": [
"jest --findRelatedTests --config .jest.js",
"git add"
],
"src/utils/*.js": [
"jest --findRelatedTests --config .jest.js",
"git add"
]
}
}
...
}
複製代碼
規範化commit信息,有助於將修改的問題進行分類,快速定位修復的問題,並提取出有用的提交信息來生成最終的changelog文件。
社區中比較好的方案是commitizen和conventional-changelog。
commitizen
用來規範commit message,比較主流是的是使用AngularJS的規範來編寫commit message。
全局安裝commitizen
sudo npm install -g commitizen複製代碼
而後在項目裏執行下面的語句,讓commitizen支持AngularJS的message規範。
commitizen init cz-conventional-changelog --save-dev --save-exact複製代碼
執行之後,會在項目的devDependencies加入cz-conventional-changelog這個依賴,並在package.json中加入以下的配置項
"config": {
"commitizen": {
"path": "cz-conventional-changelog"
}
}複製代碼
完成上面的步驟之後,之後全部的git commit 命令都用git cz來替換。
AngularJS的提交風格以下
<type>(<scope>): <subject>
// 空一行
<body>
// 空一行
<footer>複製代碼
由Header、Body和Footer三個部分組成,其中Header是必須的,Body和Footer均可以省略。
type表示commit的類型,有以下七種類型:
feat:新功能(feature)
fix:修補bug
docs:文檔(documentation)
style: 格式(不影響代碼運行的變更)
refactor:重構(即不是新增功能,也不是修改bug的代碼變更)
test:增長測試
chore:構建過程或輔助工具的變更
scope表示此次commit的影響範圍
subject是commit的簡單描述,不能超過50個字符
body是對此次commit的具體描述,能夠是多行的
footer只用於兩種狀況
不兼容變更,若是是上個版本不兼容的改動,用BREAKING CHANGE做爲開頭
關閉 Issue,例如 Closes #234
若是全部的提交記錄都符合AngularJS的規範,那麼可使用命令來自動生成changelog文件。
必須安裝conventional-changelog-cli的依賴
npm install --save-dev conventional-changelog-cli
{
"scripts": {
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -w -r 0"
}
}複製代碼
生成的文檔只會收集type爲feat、fix還有Breaking changes這三種類型的提交記錄。
若是強制使用的話,能夠validate-commit-msg來對commit message進行校驗,若是格式不符合,就阻止提交。
若是不想使用規範化的提交,也可使用下面的方法,收集全部的提交信息來生changelog。
gitCommitMsg.js
const { execFile } = require('child_process');
const fs = require('fs');
const path = require('path');
const formatOptions = ['log', '--pretty=format:%ad %cn committed %s %h', '--date=format:%Y-%m-%d'];
const writeStream = fs.createWriteStream(path.join(process.cwd(), 'CHANGELOG.md'));
const child = execFile('git', formatOptions, {
cwd: process.cwd(),
maxBuffer: Infinity,
});
child.stdout
.pipe(writeStream);複製代碼
在項目開發的時候都是經過npm去安裝第三方包到本地的node_modules裏面,並且爲了加快項目的構建速度,會忽略對node_modules裏面模塊的處理,因此這就須要咱們在開發npm包的時候提早作好編譯打包的工做。
通常來講,用於node環境的包,只要提供符合CMD規範的包便可,可是用於web的包,就須要提供更多的選項。
lib:符合commonjs規範的文件,通常放在lib這個文件夾裏面,入口是mian
es:符合ES module對方的文件,通常放在es這個文件夾裏面,入口是module
dist:通過壓縮的文件,通常是能夠經過script標籤直接引用的文件
Babel是JavaScript的一個編譯器,用來將ES6的代碼轉換成ES5的代碼,關於babel更多的介紹能夠參考以前的文章babel從入門到放棄。
TypeScript是JavaScript的一個超集,支持JavaScript的多有語法和語義,對於一些新的語法也會有及時的跟進,而且在此之上提供了更多額外的特性,好比靜態類型和風豐富的語法。TS的代碼也能夠經過編譯轉換成正常的JavaScript代碼,全部如今也有一種思路是用JavaScript的語法去進行開發,可是用TS的編譯器對代碼進行轉換。
webpack是如今主流的打包工具,有着活躍和龐大的社區支持。rollup號稱是下一代打包方案,不少實驗性的功能都是它最早實現的,好比scope hoisting 和tree shaking。webpack因爲本身實現了一套相似於node的module方案,因此在打包文件的大小上以及文件的可讀性上都存在必定的問題,並且相比於webpack複雜的配置文件,rollup的配置相來講更簡單。因此庫文件的打包比較好的方案是rollup + babel。
在通常的迭代過程當中,步驟多是
修改完本地代碼之後,提交此次的修改,運行git add . && git commit && git push
修改package.json中的version字段,實現版本號的自增
運行git add . && git commit && git push
給這個版本打一個tag,git tag <package.version> && git push --tags
發佈到npm,運行npm publish
npm version用來自動更新npm包的version,對SemVer的版本規範有很好的支持。
npm version [<newversion> | major | minor | patch | premajor | preminor | prepatch | prerelease [--preid=<prerelease-id>] | from-git]
例:初始版本爲1.0.0
npm version prepatch
//預備補丁版本號 v1.0.1-0
npm version prerelease
//預發佈版本號 v1.0.1-1
npm version patch
//補丁版本號 v1.0.2
npm version preminor
//預備次版本號 v1.1.0-0
npm version minor
//次版本號 v1.1.0
npm version premajor
//預備主版本號 v2.0.0-0
npm version major
//主版本號 v2.0.0
經常使用的是major
,minor
和patch
,分別對應規範中的x,y,z。
當倉庫已經被git初始化了,那麼運行npm version
修改完版本號之後,還會運行git add 、git commit和git tag的命令,其中commit的信息默認是自改完的版本號。若是想自定義commit的信息,能夠提供 -m 或者 —message 的選項,若是有"%s"的符號,會被替換爲版本號。
npm version patch -m "Upgrade to %s for reasons"
npm version還支持pre和post的鉤子,能夠利用這兩個鉤子函數作一些自動化的配置。
在preversion這個鉤子中,生成changelog文件,並將新生成的文件推入到緩存區中。
在postversion這個鉤子中,進行倉庫和tag的推送。
簡化操做,能夠作以下配置
{
"scripts": {
"simple": "node gitCommitMsg.js", //生成簡單的changelog文件
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0",
"preversion": "npm run changelog && git add CHANGELOG.md",
"postversion": "git push && git push --tags",
"x": "npm version major -m 'Upgrade version to %s '",
"y": "npm version minor -m 'Upgrade version to %s '",
"z": "npm version patch -m 'Upgrade version to %s '"
},
}複製代碼
和npm version同樣,在執行npm publish這個命令的時候,npm會依次執行scripts中的prepublish、publish、postpublish的命令,若是有定義的話。
npm5的版本中,prepublish用來代替prepublishOnly這個鉤子,只在publish以前進行調用,建議npm升級到5及以上的版本,保證鉤子的一致性。
在包發佈以前和以後,咱們能夠利用prepublish和postpublish這個兩個鉤子作一些相關的工做。
在開發中,咱們都是使用ES6的語法來進行開發的,因此在發佈的時候會涉及到代碼的編譯。通常的開源項目,好比redux、antd,都會提供最少三種的文件格式
一、通過壓縮的dist文件,通常放在dist文件夾中,能夠用script進行直接引用
二、符合commonjs規範的文件,通常放在lib文件夾中
三、符合ES6模塊規範的文件,通常放在es文件夾中
四、符合umd經過規範的文件,在瀏覽器和node中均可以使用
因此具體的流程爲:
prepublish,對包進行打包編譯
publish,只發布編譯後的文件
postpublish,刪除編譯生成的文件
"scripts": {
"es": "tools run es",
"lib": "tools run commonjs",
"dist:umd": "tools run dist:umd",
"dist:cjs": "tools run dist:cjs",
"dist:es": "tools run dist:es",
"dist:min": "tools run dist:min",
"compile": "npm run es && npm run lib",
"dist": "npm run dist:umd && npm run dist:cjs && npm run dist:es && npm run dist:min",
"prepublish": "npm run compile && npm run dist",
"postpublish": "rm -rf es && rm -rf lib && rm -rf dist",
}複製代碼
使用npm publish發佈包的時候,會有一個--tag的選項,若是不提供的話,會默認設置爲latest,而且在使用npm install某個包的時候,默認也會安裝latest這個tag的包。
可是在進行包的迭代的時候,可能會須要發佈不一樣的版原本作新功能的測試,這時候就須要結合SemVer和--tag來進行相應的處理。
npm publish --tag <tagname>
使用上面的命令,能夠發佈對應的dist-tag。
若是咱們想進行下一個大版本的迭代,並用next的dist-tag來表示
npm publist --tag next
若是用戶想安裝這個tag下的包,可使用下面的命令
npm install package@next
能夠經過dist-tag來查看某個包的dist-tag
npm dist-tag ls redux
latest: 4.0.0
next: 4.0.0-rc.1
當預發版本穩定之後,可使用npm dist-tag add beta latest
把預發版本設置爲穩定版本。
{
"lint": "eslint --fix src/",
"lint:style": "stylelint --fix 'src/**/*.less'",
"test": "cross-env BABEL_ENV=test jest --colors --config .jest.js",
"pre-commit": "lint-staged",
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0",
"preversion": "npm run changelog && git add CHANGELOG.md",
"postversion": "git push && git push --tags",
"x": "npm version major -m 'Upgrade version to %s '",
"y": "npm version minor -m 'Upgrade version to %s '",
"z": "npm version patch -m 'Upgrade version to %s '",
"es": "tools run es",
"lib": "tools run commonjs",
"dist:umd": "tools run dist:umd",
"dist:cjs": "tools run dist:cjs",
"dist:es": "tools run dist:es",
"dist:min": "tools run dist:min",
"compile": "npm run es && npm run lib",
"dist": "npm run dist:umd && npm run dist:cjs && npm run dist:es && npm run dist:min",
"prepublish": "npm run compile && npm run dist"
"postpublish": "rm -rf es && rm -rf lib && rm -rf dist",
}複製代碼
有三個方法能夠控制npm發佈的包中包含哪些文件
package.json#files
files字段是一個數組,用來表示能夠包含哪些文件,格式和.gitignore的寫法同樣
.npmignore
這個文件用來表示哪些文件將被忽略,格式和.gitignore的寫法同樣
.gitignore
也能夠用來表示要忽略哪些文件
這三個的優先級是files > .npmignore > .gitignore
files包含的文件,就算出如今.npmignore和.gitignore,也不會被忽略。若是既沒有files字段,也沒有.npmignore文件,那麼npm會讀取.gitignore文件,忽略裏面的文件。
package.json#mai
n 和 package.json#module
這兩個字段是用來指定npm包的入口文件,可是二者有必定的不一樣。
npm在一開始的時候,是node的包管理平臺,全部的包都是基於CommonJS 規範規範的,main這個字段是npm自帶的,通常表示符合CommonJS規範的文件入口。
rollup實現了基於ES模塊靜態分析,對代碼進行Tree Shaking,它經過識別package.json中的module字段,將它當成是符合ES模塊規範的文件入口。webpack以後也進行跟進,也能識別module字段,而且在webpack的默認配置中,module的優先級要高於main,所以符合ES模塊規範的代碼能進行Tree Shaking,減小項目最終打包出來的代碼。
由於通常的項目在配置babel的時候,爲了提升構建速度,都會忽略node_modules裏面的文件,因此module入口的文件最好是符合ESmodule規範的ES5的代碼,webpack最終會把ESmodule轉換爲它本身的commonjs規範的代碼。
package.json#sideEffect
這個字段是webpack4中新增的一個特性,用來表示npm包的代碼是否具備反作用。ES6的代碼在通過babel編譯爲ES5的代碼後,就算是符合ES6的模塊規範,也會出現UglifyJs沒法Tree Shaking的問題。webpack4經過sideEffect這個字段,使UglifyJs強行進行Tree Shaking。
sideEffect能夠設置爲Boolean或者數組
當爲false時,代表這個包是沒有反作用的,能夠進行按需引用
若是爲數組時,數組的每一項表示的是有反作用的文件
在組件庫開發的時候,若是有樣式文件,須要把樣式文件的路徑放到sideEffect的數組中,由於UglifyJs只能識別js文件,若是不設置的話,最後打包的時候會把樣式文件忽略掉。
{ "sideEffects": ["components/**/*.less"] }複製代碼
npm全局安裝後,它的register是 registry.npmjs.org ,若是你使用淘寶的鏡像重寫了register,那麼可能會在登錄和發佈的時候出錯。
npm config list @cfe:registry = "mirrors.npm.private.caocaokeji.cn/repository/…"
registry = "registry.npm.taobao.org/"
可使用下面的命令進行登錄和發佈
npm login --registry registry.npmjs.org
npm publish --registry registry.npmjs.org
或者在開發npm包的時候,將registry換成npm的官方地址,開發完之後再換回淘寶的鏡像
npm config set set registry www.npmjs.com/
npm config set registry registry.npm.taobao.org
在開發包的時候,會遇到調試問題,但願可以一邊開發一邊調試,不用頻繁的去發佈版本。
使用npm link能夠達到這個效果,它會在在全局的node_modules目錄中生成一個符號連接,指向模塊的本地目錄。
假設你要開發一個包,叫tool,須要在本地的項目work-center中去使用 在命令行中進入tool的目錄,運行npm link這個命令,就會生成一個符號連接。
進入項目work-center的目錄,運行npm link tool,就可使用這個包了。
tool的全部改動都會映射到安裝的項目中,可是帶來的問題就是一處改動多處影響。
在調試結束後,運行npm unlink tool來刪除符號連接。
在Mac上使用oh-my-zsh能夠提升命令行的開發效率,具體的配置能夠參考這篇文章mac下oh-my-zsh的配置
安裝了oh-my-zsh之後,能夠簡化git的命令行操做,提升鍵盤的壽命,經常使用命令以下
zsh-git快捷鍵
gst - git status
gl - git pull
gp - git push
ga - git add
gcmsg - git commit -m
gco - git checkout
gcm - git checkout master
monorepo 是單代碼倉庫,與之對應的是multirepo,多代碼倉庫。
monorepo是把全部的module都放在一個代碼倉庫中,進行統一管理;multirepo是把module拆分開來,單獨去管理。multirepo的問題是issue、changelog和版本號很差管理;monorepo的問題是單個倉庫代碼量比較大。如今一些主流的開發項目,好比babel、react、vue、vue-cli,都是使用monorepo的方式來管理代碼倉庫的;rollup和antd是使用multirepo。
lerna是babel官方開源的monorepo管理工具。