無腦發布 npm
比如老王我,用npm init新建一個包,改把改把,然后來個npm publish,so easy ??!
Too young too naive, baby ??!
請容我講述一些發布程序中踩過的坑,
首先,算了也可以之后有空再說,我們需要通讀npm的配置檔案,
package.json doc
通用性??
指定發布檔案
利用package.json中files欄位精簡發布體積,
{
"files": ["dist", "lib", "module"]
}
若不指定files,每次發布會把所有不以.開頭的檔案都發布出去,導致發布體積過大(node_modules默認也不會被發布),
README.md作為主檔案,加不加都會發布,package.json也是,
指定源代碼
{
"source": "src/index.ts",
"repository": {
"type": "git",
"url": "https://github.com/yourname/yourproject.git"
}
}
通常來說我是不在npm發布中包括源代碼的,因此都沒有加過source欄位,只是用repository來告知一下git倉庫地址即可,
如果倉庫是內部倉庫或私人倉庫并不對外,則source欄位就有用了,將源代碼發布后可讓人幫忙debug找問題,
注意如果有source,則files也要加上souce對應的檔案或檔案夾,
發布sourcemap
一般來說我們發布的都是經過編譯的代碼,為了給使用者方便除錯,只要不是原始碼,都要有對應的sourcemap檔案,例如發布了一個dist/index.js則也需要一個dist/index.js.map檔案與之配套,
指定安裝源
如果你從來不用私有源,可跳過該項,
利用.npmrc指定安裝源,用于當前專案與你的全域配置區分開,
否則當前專案很可能指定的內部npm源,導致外部用戶無法利用lock檔案安裝,
例如
registry=https://registry.npmjs.org/
精確指定dependencies、devDependencies、peerDependencies
dependencies要盡量少,只有在運行時確實用到才放進去,
依賴的版本號要清晰指明,如"react": "16.x || 17.x"
否則,如果指定了"react": "17.0.0",則在使用了react 16的專案中,會引入兩份react,造成一些莫名其妙的問題,
這種情況,react應放到peerDependencies中,
指定發布目標
如果你從來不在私有源發布,可跳過該項,
在package.json中指定發布地址,在當前包與全域配置不一致時非常必要,
{
"publishConfig": {
"registry": "https://registry.npmjs.org"
}
}
sideEffects
對應配置:
{ "sideEffects": false }
作用:在打包時進行treeshake可根據是否使用而優化相關的代碼,
如果sideEffects為true,則一旦引入,不管是否呼叫都不能被treeshake掉,
專用性??
型別配套
無論針對哪個環境,目前自帶型別已經是既成事實的標配,
記得生成型別的.d.ts檔案,并在package.json中指定,
{
"types": "type/index.d.ts",
"typings": "type/index.d.ts"
}
我一般會用一個專用的tsconfig.declaration.json來專門生成型別:
{
"extends": "./tsconfig.json",
"compilerOptions": {
"noEmit": false,
"emitDeclarationOnly": true,
"declaration": true,
"outDir": "types"
}
}
作為后端庫
package.json中指定main欄位,
編譯結果需要在nodejs環境中運行,輸出commonjs格式模塊,
為了兼容最新與將來,同時也要輸出esmodule格式模塊,
相關配置:
{
"main": "lib/index.js",
"module": "module/index.js",
"jsnext:main": "module/index.js"
}
module與jsnext:main都是指esmodule格式,只是為了兼容某些特殊環境的別名,可能還有其他別名單我暫時就見過這倆,
其中module中的檔案推薦使用特定的后綴名,例如.esm.js或.mjs,但在一些工程相關工具中是否會有未知為題,不好說,
未來已來,現在大部分前端工程工具都會優先使用module指定的檔案,單如果沒有指定module,也會為了兼容去加載main,
作為前端庫
前端庫其實要求比后端庫更高,為啥?
因為現代前端開發環境要求支持所有后端環境,并延伸出前端環境的額外支持,也就是說后端庫要求一般是前端庫要求的子集,
需要擴展的是純前端環境的運行格式,老格式amd已經被淘汰可以不用考慮,現在基本都被umd格式統一,
{
"main": "lib/index.js",
"module": "module/index.js",
"unpkg": "dist/index.js",
"umd:main": "dist/index.js",
"jsdelivr": "dist/index.umd.production.min.js"
}
其中unpkg,umd:main,jsdelivr都是為了更廣泛兼容的指向瀏覽器環境運行的同一個目標別名,
通常來說commonjs,esmodule,umd都不會將其依賴的其他包包括進去,只是在運行時才加載,
還有一種情況,可能只有我自己用到過,就是發布包中有些東西與外部環境有沖突,因此除了這些通用模式之外我又加了一個independent(取名叫standalong也比較合適)格式,將這個包的所有依賴都封裝進去,可以不依賴外部環境獨立使用,
例如mobx-value的獨立運行檔案,
mobx-value independent
注意瀏覽器環境輸出的都是優化后的.production.min格式,也必須同時輸出.development后綴的開發模式,為了方便使用者除錯方便,
因為最大的使用者,往往就是我們自己,不要連自己都糊弄了事~
作為命令列工具
多配置兼容
命令列工具一般需要很多引數,例如tsc,當引數過多時沒人愿意每次都輸入長長的引數,因此需要組態檔的支持,
那么選哪種配置格式呢?
此時cosmiconfig隆重登場!以一句名言形容,小孩子才做選擇,成年人全都要!
兼容各種配置,各種位置,詳情參見其api,
還有一點,如果需要讀取一些周邊的json配置,不要用原生的JSON.parse,很多json是帶注釋的或者撰寫不規范,用json5讀取兼容好,
還有一個精簡版:lilconfig,功能差不多,我下次打算試試,
配置檔案型別校驗
剛入門typescript時,我嘗試用typescript作為組態檔,然后在運行時利用型別機制達到校驗配置的目的,
但這樣會丟失很多靈活性,限制死了組態檔的來源與格式,并由于庫的typescript環境與應用所在的typescript環境不一致,也導致了很多工程問題(對我說的就是ts-gear),
后來發現通過注釋檔案的方式,js檔案中也同樣可以校驗型別,而且js檔案對運行時更友好,
例如webpack.config.js這樣配置
/**
* @type {import('webpack').Configuration}
* */
const config = {...}
export default config
組態檔運行時校驗
我們的程式要讀配置,但配置是使用者提供的,誰知道用戶會寫些什么,即使有上面那步提到的型別校驗把關,也會有很多邊界問題型別根本管不了,
因此,運行時配置資料校驗就是必備環節,
不光是校驗不通過時終止運行,還必須給出一個合理且精準的錯誤提示,
推薦一個協議、兩個校驗工具與一個漂亮的格式化提示工具,
協議是json schema,校驗工具為joi或ajv,提示輸出工具為chalk,
指定可運行檔案
在package.json中指定bin:
{
"bin": "bin/run.js"
}
對于大部分js腳本,都要在運行檔案頭部指定運行環境,
#! /usr/bin/env node
然后別忘了在發布前添加可執行屬性,務必整合在自動化發布腳本中,
chmod +x bin/run.js
可呼叫api
例如babel,我們不光能使用@babel/cli在命令列使用,也可以在自己的程式里import babel from 'babel'來呼叫其api,
一個命令列工具通常也是一個第三方庫,方便集成到呼叫者自身的腳本與環境中,
其他特定環境
例如針對react-native,這個我就見過,沒實際用過,
{
"react-native": "dist/index.esm.js"
}
最后不論什么格式,都記得輸出配套sourcemap的.map檔案,
健壯性??
指定運行環境:engine與os
尤其對于命令列工具,這倆點很重要,不然很容易就換個人換個電腦就莫名報錯,
{
"engine": "node>=14",
"os": ["linux", "darwin"]
}
有否配套測驗用例
- 有可運行的配套測驗用例,
- 在
README.md上有可見的測驗覆寫率統計,讓人可以放心使用,
測驗用例放在哪?
最初我習慣按照jest推薦的模式,將所有測驗用例放在__tests__檔案夾內,
最近兩年看了好多別的語言的單測用例,我現在更傾向于將測驗檔案與源檔案放在一起,因為測驗用例,就是源代碼的一部分!
比如以下這種目錄結構
src/setter.ts
src/setter.test.ts
測驗運行時機
npm prepublishOnly的鉤子一定要加上運行測驗用例,
有余力的情況,可以再配置個額外的流水線,github上有好多免費的配套流水線,自己折騰折騰,
代碼校驗配套
專案必須有一個較好的檔案規則校驗流程,大多數情況我使用eslint,然后配上airbnb與prettier的校驗規則,
校驗有兩個重要作用,一個是真的能解決很多隱性bug,另一個是代碼漂亮,之后看你專案原始碼的人也會覺得舒服,關鍵是面試時也能拿的出手,
如果有面試者給我看自己的開源作品,如果代碼風格都不行,立即就判定不行,也不用再看什么邏輯能力了,招進來也是挖坑,
好的代碼風格必須依賴校驗工具,最好把校驗流程也集成到發布的鉤子上,
推廣性??
檔案
使用.markdownlint配置規范自己的markdown檔案,否則很容易寫飛了,
要不人家一看檔案,專案質量很容易就露餡了不是??
配套展示用例
- 一個方法是在專案中自帶一個可運行的樣例,讓人
clone之后運行指定命令即可查看樣例, - 更好一些,部署一個可以在線查看的例子,并在主檔案上附上直達鏈接,
- 更進一步,專案增大之后,需要說明的地方越來越多,一個
README已經太長,使用docusaurus等類似的工具部署一個獨立的檔案站點,
有否自動化版本管理
Why?因為版本號與兼容性是強相關的,具體參考semver規范,
- 使用
husky/yorkie等規范提交日志, - 使用
standard-version等自動生成CHANGELOG并根據規則自動提升版本號,
最后留個作業
- 你有什么
npm發布時的關鍵經驗這里沒提到的,幫我補充下?? - 當我們再一次運行
npm publish,腦編譯一下,想想這期間都發生了些什么,還少些什么?
作者:京東零售 王凡
內容來源:京東云開發者社區
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/553392.html
標籤:其他
下一篇:返回列表
