一文詳解如何使npm-scripts更好維護(hù)的配置方法
前言
當(dāng)一個(gè)項(xiàng)目越來(lái)越大,但是團(tuán)隊(duì)對(duì)于項(xiàng)目目錄配置、命名風(fēng)格、模塊劃分、工程腳本等方面沒(méi)有做好完備的團(tuán)隊(duì)規(guī)范時(shí),就會(huì)面臨各種方法應(yīng)用千人千面,接手和維護(hù)的心智負(fù)擔(dān)大的問(wèn)題,其中scripts
配置就是一個(gè)迭代不那么容易收斂的一項(xiàng)配置。
比如張三某天開(kāi)發(fā)了一段腳本,寫(xiě)入xxx
配置進(jìn)行使用(其實(shí)也是一段很有用的腳本),除非項(xiàng)目有完善的開(kāi)發(fā)文檔,否則后來(lái)的人根本不知道有這個(gè)功能,甚至根本不會(huì)想到去用,或者因?yàn)椴恢蓝秩ブ匦略燧喿?..
緣和?
最近在接手一個(gè)迭代了很久的項(xiàng)目時(shí),上手看到的package.json
是這樣的:
"scripts":?{ ??"analyze":?"cross-env?ANALYZE=1?umi?build", ??"start":?"cross-env?UMI_ENV=dev?umi?dev", ??"dev":?"npm?run?start:dev", ??"start:dev":?"cross-env?REACT_APP_ENV=dev?MOCK=none?UMI_ENV=dev?umi?dev", ??"start:no-mock":?"cross-env?MOCK=none?UMI_ENV=dev?umi?dev", ??"start:no-ui":?"cross-env?UMI_UI=none?UMI_ENV=dev?umi?dev", ??"start:pre":?"cross-env?REACT_APP_ENV=pre?UMI_ENV=pre?umi?dev", ??"start:test":?"cross-env?REACT_APP_ENV=test?MOCK=none?UMI_ENV=test?umi?dev", ??"start:lcic":?"cross-env?REACT_APP_ENV=dev?MOCK=none?UMI_ENV=lcic?umi?dev", ??"build:test":?"cross-env?UMI_ENV=test?umi?build", ??"build:pt":?"cross-env?UMI_ENV=pt?umi?build", ??"build:pre":?"cross-env?UMI_ENV=pre?umi?build", ??"build:prod":?"cross-env?UMI_ENV=prod?umi?build", ??"build:canary":?"cross-env?UMI_ENV=canary?umi?build", ??"build:hw":?"cross-env?UMI_ENV=hw?umi?build", ??"build:ms":?"cross-env?UMI_ENV=ms?umi?build", ??"deploy":?"npm?run?site?&&?npm?run?gh-pages", ??"gh-pages":?"gh-pages?-d?dist", ??"i18n-remove":?"pro?i18n-remove?--locale=zh-CN?--write", ??"postinstall":?"umi?g?tmp", ??"lint":?"umi?g?tmp?&&?npm?run?lint:js?&&?npm?run?lint:style?&&?npm?run?lint:prettier", ??"lint-staged":?"lint-staged", ??"lint-staged:js":?"eslint?--ext?.js,.jsx,.ts,.tsx?", ??"lint:fix":?"eslint?--fix?--cache?--ext?.js,.jsx,.ts,.tsx?--format=pretty?./src?&&?npm?run?lint:style", ??"lint:js":?"eslint?--cache?--ext?.js,.jsx,.ts,.tsx?--format=pretty?./src", ??"lint:prettier":?"prettier?--check?"src/**/*"?--end-of-line?auto", ??"lint:style":?"stylelint?--fix?"src/**/*.less"?--syntax?less", ??"openapi":?"umi?openapi", ??"precommit":?"", ??"prettier":?"prettier?-c?--write?"src/**/*"", ??"pretest":?"node?./tests/beforeTest", ??"test":?"umi?test", ??"test:all":?"node?./tests/run-tests.js", ??"test:component":?"umi?test?./src/components", ??"tsc":?"tsc?--noEmit", ??"prepare":?"husky?install" },
不知道你看到這樣的配置第一時(shí)間反應(yīng)是怎樣的,我的感受是“頭皮發(fā)麻”。問(wèn)題是,這些腳本分別是什么作用?什么場(chǎng)景下用?
如果注釋就好了對(duì)不對(duì)
可是package.json
它不允許寫(xiě)注釋??!
嘗試
有沒(méi)有可能,我們可以像以下這樣維護(hù)一個(gè)項(xiàng)目的scritps
呢?這樣接手的人也清楚的知道每個(gè)命令代表什么含義,同時(shí)也能夠單獨(dú)維護(hù)甚至復(fù)用在多個(gè)項(xiàng)目上。
//?假如有這么一個(gè)配置文件 [{ ??cmd:?'start:dev', ??script:?'cross-env?REACT_APP_ENV=dev?max?dev', ??desc:?'啟動(dòng)本地開(kāi)發(fā)環(huán)境,代理開(kāi)發(fā)環(huán)境API', }, ?{ ???cmd:?'start:test', ???script:?'cross-env?REACT_APP_ENV=test?max?test', ???desc:?'啟動(dòng)本地開(kāi)發(fā)環(huán)境,代理測(cè)試環(huán)境API', ?}]
想法感覺(jué)還可以,但是怎么實(shí)現(xiàn)呢?粗略的想象一下先:
想法1: 能不能攔截npm run xxx
動(dòng)作,讓執(zhí)行xxx
時(shí)去執(zhí)行自定義的配置文件中的命令而不是package.json
想法2: 還是用配置,既然想要優(yōu)化這個(gè)過(guò)程,能不能只執(zhí)行 app xxx
(app假設(shè)是我要做的這個(gè)工具),那run
也省掉了啊
結(jié)論是:
- 想法1經(jīng)過(guò)一番搜刮資源和查找npm文檔,發(fā)現(xiàn)并沒(méi)有所謂運(yùn)行
npm run xxx
之前可以介入的鉤子,因此直接破滅 - 想法2顯然更好一點(diǎn),但是
app
這個(gè)腳本就得裝在全局了,否則實(shí)現(xiàn)不了app xxx
,要么就只能裝在項(xiàng)目里通過(guò)npx app xxx
去調(diào)用
期間還了解了scripty這個(gè)插件,發(fā)現(xiàn)它的過(guò)程很雞肋,相當(dāng)于把命令和腳本寫(xiě)了兩遍,what?怎么可能,我那么懶!
因此經(jīng)過(guò)嘗試,只能采取想法2去實(shí)現(xiàn)這個(gè)功能了。
盤(pán)點(diǎn)需求
如上文的思路,一份配置文件肯定是必要的,那么定義的形態(tài)就以上文的為基準(zhǔn)了。
- 我希望可以提供針對(duì)不同構(gòu)建工具/平臺(tái)的通用命令集,比如本地啟動(dòng)命令
比如對(duì)于vite
,通常是這樣的:vite
對(duì)于webpack
,通常是這樣的:
webpack-dev-server --mode development
對(duì)于umi,最常見(jiàn)的是這樣的:
cross-env UMI_ENV=dev umi dev
因此對(duì)于這些每個(gè)項(xiàng)目必備的命令,需要默認(rèn)支持,就不用單獨(dú)去寫(xiě)了
- 既然我都要借助這個(gè)工具去提升開(kāi)發(fā)體驗(yàn)了,那對(duì)應(yīng)的提示是不是得到位,接手的人一步就能知道所有命令的作用,比如:
- 我能不能直接對(duì)老項(xiàng)目直接生成一套標(biāo)準(zhǔn)配置,我再去補(bǔ)充
desc
呢
實(shí)現(xiàn)
實(shí)現(xiàn)過(guò)程很簡(jiǎn)單,最終就是直接采用child_process.exec
去執(zhí)行了原始腳本:
executeScript(cmd:?string)?{ ??exec(cmd,?(err,?sto)?=>?{ ????if?(err)?{ ??????Log.error(err.stack) ????}?else?{ ??????Log.info(sto) ????} ??}) }
健壯性目前還比較欠缺,僅實(shí)現(xiàn)了上述幾個(gè)需求點(diǎn)的基礎(chǔ)功能,后續(xù)會(huì)進(jìn)行完善。想要了解原理的可以看源碼,整體實(shí)現(xiàn)就只有100多行代碼,如有需要可以進(jìn)行二次改造在企業(yè)內(nèi)部推廣使用。
使用
安裝
npm i npm-scripts-proxy -g
生成模板
nsp init
寫(xiě)模板
//?nsp.config.mjs import?{?defineNSPConfig,?presets?}?from?'npm-scripts-proxy' export?default?defineNSPConfig({ ??scripts:?[ ????{ ??????cmd:?'test', ??????script:?'echo?"Error:?no?test?specified"', ??????desc:?'測(cè)試程序', ????}, ????{ ??????cmd:?'build:test', ??????script:?'node?build.js', ??????desc:?'打包測(cè)試環(huán)境', ????} ??], ??extends:?presets.vite, })
運(yùn)行命令
nsp xxx
總結(jié)
其實(shí)到最后發(fā)現(xiàn),這個(gè)工具就解決了一個(gè)問(wèn)題,那就是標(biāo)題提出的問(wèn)題,可能它不是最好的解決方案,但是項(xiàng)目一定是越做越大,必然是避免不了冗余且復(fù)雜的。而如果在開(kāi)發(fā)體驗(yàn)層面可以有一點(diǎn)點(diǎn)提升,省去我們接手項(xiàng)目時(shí)的一些“頭皮發(fā)麻”的體驗(yàn),寫(xiě)代碼的心情應(yīng)該也會(huì)好一點(diǎn)吧。
最近在看美團(tuán)Rome
的演進(jìn)史時(shí),負(fù)責(zé)人講到一些關(guān)于Rome
在提升開(kāi)發(fā)體驗(yàn)層面的考慮,感覺(jué)很不錯(cuò),拋開(kāi)提升效率從而實(shí)現(xiàn)為企業(yè)降本增效不談,“開(kāi)發(fā)體驗(yàn)”何嘗不是一個(gè)很重要且值得關(guān)注的事情呢。
一個(gè)問(wèn)題
通過(guò)實(shí)現(xiàn)過(guò)程可以知道,這個(gè)方案其實(shí)就是間接的去執(zhí)行了npm run xxx
,從而不必維護(hù)package.json
中的配置,改去維護(hù)體驗(yàn)更好的配置方式。帶來(lái)的問(wèn)題是,已有的CI
構(gòu)建流程就需要替換,如果項(xiàng)目很多那就需要花相應(yīng)的成本去改造,因此實(shí)際應(yīng)用還需要綜合評(píng)估一下才行,不過(guò)它確實(shí)有效的解決了一開(kāi)始提到的問(wèn)題,是一個(gè)值得嘗試的方案。興趣的朋友可以去看源碼,有更好方案的也可以評(píng)論區(qū)留言一下,讓路過(guò)的開(kāi)發(fā)者也借鑒一下。
以上就是一文詳解如何使npm-scripts更好維護(hù)的詳細(xì)內(nèi)容,更多關(guān)于npm-scripts維護(hù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Typescript井字棋的項(xiàng)目實(shí)現(xiàn)
本文主要介紹了Typescript井字棋的項(xiàng)目實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08JavaScript實(shí)現(xiàn)郵箱后綴提示功能的示例代碼
這篇文章主要介紹了JavaScript實(shí)現(xiàn)郵箱后綴提示功能的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-12-12JS使用tofixed與round處理數(shù)據(jù)四舍五入的區(qū)別
js中一般使用tofixed與round處理數(shù)據(jù)四舍五入,那么tofixed與round有什么區(qū)別呢?下面小編給大家分享JS使用tofixed與round處理數(shù)據(jù)四舍五入的區(qū)別,需要的朋友參考下吧2017-10-10iframe父子頁(yè)面實(shí)現(xiàn)共用滾動(dòng)條的常見(jiàn)方法
在開(kāi)發(fā)過(guò)程中,有時(shí)候需要用到iframe復(fù)用不同域名下的頁(yè)面內(nèi)容,為了提供連貫的用戶(hù)體驗(yàn),經(jīng)常需要在主頁(yè)面(父頁(yè)面)和iframe子頁(yè)面之間共享滾動(dòng)位置,本文將介紹其中較為常見(jiàn)的一種方法來(lái)實(shí)現(xiàn)iframe父子頁(yè)面共用滾動(dòng)條,需要的朋友可以參考下2024-05-05在TypeScript項(xiàng)目中進(jìn)行BDD測(cè)試
這篇文章主要介紹了在TypeScript項(xiàng)目中進(jìn)行BDD測(cè)試,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04JS中onpropertychange和onchange事件區(qū)別小結(jié)
當(dāng)一個(gè)HTML元素的屬性用js改變的時(shí)候,都能通過(guò)onpropertychange來(lái)捕獲。例如一個(gè)文本text對(duì)象的value屬性被頁(yè)面的腳本修改的時(shí)候,onchange無(wú)法捕獲到,而onpropertychange卻能夠捕獲。2010-07-07詳解JavaScript對(duì)象轉(zhuǎn)原始值
這篇文章主要為大家介紹了vue組件通信的幾種方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2021-12-12小程序?qū)崿F(xiàn)簡(jiǎn)單語(yǔ)音聊天的示例代碼
這篇文章主要介紹了小程序?qū)崿F(xiàn)簡(jiǎn)單語(yǔ)音聊天的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07基于postman獲取動(dòng)態(tài)數(shù)據(jù)過(guò)程詳解
這篇文章主要介紹了基于postman獲取動(dòng)態(tài)數(shù)據(jù)過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09