1. 前言
大家好,我是若川。持續組織了近一年的源碼共讀活動,感興趣的可以?加我微信?ruochuan12?參與,每周大家一起學習200行左右的源碼,共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》?包含包含jQuery
、underscore
、lodash
、vuex
、sentry
、axios
、redux
、koa
、vue-devtools
、vuex4
、koa-compose
、vue 3.2 發布
、vue-this
、create-vue
、玩具vite
等20余篇源碼文章。歷史面試系列。另外:目前建有江西|湖南|湖北
籍前端群,可加我微信進群。
2. 前情回顧
本文提到的工具已開源,可以直接克隆拿去用,也可以自行修改使用,https://github.com/lxchuan12/mp-cli.git,求個star^_^[1]
估計有很多開發小程序的同學,還在使用微信開發者工具上傳小程序。如果你是,那么這篇文章非常適合你。如果不是,同樣也很適合你。
早在 2021年08月,我寫過一篇文章 Vue 3.2 發布了,那尤雨溪是怎么發布 Vue.js 的?
Vue 2.7
如何發布跟Vue 3.2
這篇文章類似,所以就不贅述了。
vuejs
發布的文件很多代碼我們可以直接復制粘貼修改,優化我們自己發布的流程。比如寫小程序,相對可能發布頻繁,完全可以使用這套代碼,配合miniprogram-ci[2],再加上一些自定義,加以優化。
于是今天我們來開發這樣的腳手架工具。
看完本文,你將學到:
1.?如何利用?release-it?提升版本號,自動打?tag,生成?changelog?等
2.?npm?init?原理
3.?如何寫一個腳手架工具-?如何解析?Nodejs?命令行參數?minimist-?如何選擇單選、多選?enquirer(prompt,?MultiSelect)-?等等
先看看最終開發的效果。
支持的功能

顯示幫助信息

上傳效果

3. 關于為啥要開發這樣的工具
關于小程序
ci
上傳,再分享兩篇文章。
基于 CI 實現微信小程序的持續構建[3]
小打卡小程序自動化構建及發布的工程化實踐[4] 雖然文章里不是最新的
miniprogram-ci
,但這篇場景寫得比較全面。
接著,我們先來看看 miniprogram-ci 官方文檔。
4. miniprogram-ci 官方文檔
miniprogram-ci 文檔[5]
4.1 上傳
const?ci?=?require('miniprogram-ci')
;(async?()?=>?{const?project?=?new?ci.Project({appid:?'wxsomeappid',type:?'miniProgram',projectPath:?'the/project/path',privateKeyPath:?'the/path/to/privatekey',ignores:?['node_modules/**/*'],})const?uploadResult?=?await?ci.upload({project,version:?'1.1.1',desc:?'hello',setting:?{es6:?true,},onProgressUpdate:?console.log,})console.log(uploadResult)
})()
4.2 預覽
const?ci?=?require('miniprogram-ci')
;(async?()?=>?{const?project?=?new?ci.Project({appid:?'wxsomeappid',type:?'miniProgram',projectPath:?'the/project/path',privateKeyPath:?'the/path/to/privatekey',ignores:?['node_modules/**/*'],})const?previewResult?=?await?ci.preview({project,desc:?'hello',?//?此備注將顯示在“小程序助手”開發版列表中setting:?{es6:?true,},qrcodeFormat:?'image',qrcodeOutputDest:?'/path/to/qrcode/file/destination.jpg',onProgressUpdate:?console.log,//?pagePath:?'pages/index/index',?//?預覽頁面//?searchQuery:?'a=1&b=2',??//?預覽參數?[注意!]這里的`&`字符在命令行中應寫成轉義字符`\&`})console.log(previewResult)
})()
5. Taro 小程序插件 @tarojs/plugin-mini-ci
如果使用 Taro
開發的小程序,可以直接使用。
具體如何使用參考文檔,我在本文中就不贅述了。
小程序持續集成 @tarojs/plugin-mini-ci[6]
我組織的源碼共讀第30期[7]讀的就是這個插件,非常值得學習。@tarojs/plugin-mini-ci 源碼解讀可以參考 @NewName 的源碼文章
我體驗下來的感覺有以下幾點可以優化。
不支持指定機器人
不支持不打包時上傳
不支持官方提供的更多配置
不支持選擇多個小程序批量上傳等等
如果有時間我可能給 Taro
提 PR
,當然不一定會被合并。
6. uni-app 好像沒有提供類似的插件
uni-app 好像沒有提供類似的插件。需要自己動手,豐衣足食。
7. release-it 自動提升版本、打 tag、生成 changelog 等
于是我們自己動手,豐衣足食,寫一個工具解決上面提到的問題,支持 Taro
打包后的小程序和 uni-app
打包后的,還有原生小程序上傳和預覽。
開發小工具之前,先介紹一些好用的工具。
據說很多小伙伴的項目,沒有打 tag
、沒有版本的概念,沒有生成 changelog
,沒有配置 eslint
、prettier
,沒有 commit
等規范。
這些其實不難,commit
規范一般簡單做法是安裝 npm i git-cz -D
, 在package.json
中加入如下腳本。
{"scripts":?{"commit":?"git-cz"}
}
git
提交時使用 npm run commit
即可,其他就不贅述了。
release-it,自動提升版本號,自動打 tag
,生成 changelog
等
release-it 官網倉庫[8]
npm?init?release-it
#?選擇 .release-it.json 用下面的配置,復制粘貼到 .release-it.json 中。
#?再安裝?changelog?插件
npm?i?@release-it/conventional-changelog?-D
{"github":?{"release":?false},"git":?{"commitMessage":?"release:?v${version}"},"npm":?{"publish":?false},"hooks":?{"after:bump":?"echo?更新版本成功"},"plugins":?{"@release-it/conventional-changelog":?{"preset":?"angular","infile":?"CHANGELOG.md"}}
}
這樣配置后,可以 npm run release
執行 release-it
版本。還支持 hooks 鉤子,比如提升版本號后"after:bump": "echo 更新版本成功"
,更多功能可以查看release-it 官網倉庫[9]。
7.1 npm init release-it 原理
為啥 npm init
也可以直接初始化一個項目,帶著疑問,我們翻看 npm 文檔。
`npm init`[10]
npm init
用法:
npm?init?[--force|-f|--yes|-y|--scope]
npm?init?<@scope>?(same?as?`npx?<@scope>/create`)
npm?init?[<@scope>/]<name>?(same?as?`npx?[<@scope>/]create-<name>`)
npm init <initializer>
時轉換成 npx
命令:
npm?init?foo?->?npx?create-foo
npm?init?@usr/foo?->?npx?@usr/create-foo
npm?init?@usr?->?npx?@usr/create
看完文檔,我們也就理解了:
運行 npm init release-it
=> 相當于 npx create-release-it
create-release-it[11]
npm init release-it
原理其實就是 npx create-release-it
選擇一些配置,生成 .release-it.json
或者 package.json
的 release-it
配置。
再寫入命令release
配置到 package.json
。
{"scripts":?{"release":?"release-it"}
}
最后執行 npm install release-it --save-dev
也就是源碼里的 await execa('npm', ['install', 'release-it', '--save-dev'], { stdio: 'inherit' });
。
這行源碼位置[12]
8. 小程序上傳工具實現主流程
需要支持多選,那肯定得遍歷數組。
//?代碼只是關鍵代碼,完整的可以查看?https://github.com/lxchuan12/mp-cli/blob/main/src/index.js
(async?()?=>?{for?(const?mpConfigItem?of?mpConfigList)?{try?{const?res?=?await?main({});}catch(err){console.log('執行失敗',?err);}}
})();
main
函數
const?{?green,?bold?}?=?require('kolorist');
const?step?=?(msg)?=>?console.log(bold(green(`[step]?${msg}`)));
async?function?main(options?=?{})?{const?project?=?new?ci.Project(lastProjectOptions);if?(upload)?{step('開始上傳小程序...');const?uploadResult?=?await?ci.upload(lastUploadOptions);console.log('uploadResult',?uploadResult);}if?(preview)?{step('開始生成預覽二維碼...');const?previewResult?=?await?ci.preview(lastPreviewOptions);console.log('previewResult',?previewResult);}
}
8.1 添加功能支持指定參數
使用 minimist[13] 解析命令行參數。
const?getParams?=?()?=>?{const?params?=?process.argv.slice(2);const?paramsDefault?=?{default:?{robot:?1,preview:?false,upload:?false,//?空跑,不執行dry:?false,//?根據配置,單選還是多選來上傳小程序useSelect:?false,useMultiSelect:?false,help:?false,version:?false,},alias:?{u:?'upload',r:?'robot',v:?'version',d:?'dry',s:?'useSelect',m:?'useMultiSelect',p:?'preview',h:?'help',}};return?require('minimist')(params,?paramsDefault);
};module.exports?=?{getParams,
};
8.2 支持讀取項目的 package.json
的 version
,也支持讀取自定義version
kolorist[14] 顏色輸出。
const?{?red,?bold?}?=?require('kolorist');
const?getVersion?=?()?=>?{let?version;try?{version?=?require(`${packageJsonPath}/package.json`).version;}?catch?(e)?{console.log(e);console.log(red(bold('未設置?version?,?并且未設置?package.json?路徑,無法讀取?version',),),);}return?version;
};module.exports?=?{getVersion,
};
8.3 版本描述 支持指定 git commit hash 和作者
git rev-parse --short HEAD
讀取 git
倉庫最近一次的 commit hash
。
parse-git-config
可以讀取 .git/config
配置。
//?const?path?=?require('path');
const?{?execSync?}?=?require('child_process');
const?parseGitConfig?=?require('parse-git-config');
const?getDesc?=?(projectPath,?version)?=>?{//?獲取最新?git?記錄?7位的?commit?hashlet?gitCommitHash?=?'git?commit?hash?為空';try?{gitCommitHash?=?execSync('git?rev-parse?--short?HEAD',?{cwd:?projectPath,}).toString().trim();}?catch?(e)?{console.warn('獲取?git?commit?hash?失敗');console.warn(e);}//?獲取項目的git倉庫的?user.namelet?userName?=?'默認';try?{const?{user:?{?name?=?'默認'?},}?=?parseGitConfig.sync({cwd:?projectPath,path:?'.git/config',});userName?=?name;}?catch?(e)?{console.warn('獲取?.git/config?user.name?失敗');console.warn(e);}const?desc?=?`v${version}?-?${gitCommitHash}?-?by@${userName}`;return?desc;
};module.exports?=?getDesc;
8.4 讀取配置 wx.config.js 配置(更推薦)
當前也支持讀取 .env
配置。讀取 .env
配置,可以采用 `dotenv`[15]。關于 dotenv的原理,可以看我之前寫過的文章面試官:項目中常用的 .env 文件原理是什么?如何實現?
但 wx.config.js
可以配置更多東西而且更靈活。所以更推薦。
感興趣的可以研究 vue-cli
是如何讀取 vue.config.js
配置的。圍繞工作相關的學習,往往收益更大。
//?讀取?wx.config.js?配置
const?loadWxconfig?=?(cwd)?=>?{try?{return?require(path.join(cwd,?'wx.config.js'));}?catch?(e)?{return?{error:?'未配置?wx.config.js?文件',};}
};const?parseEnv?=?()?=>?{const?cwd?=?process.cwd();let?parsed?=?{};let?wxconfig?=?loadWxconfig(cwd);if?(wxconfig.error)?{let?dotenvResult?=?require('dotenv').config({path:?path.join(cwd,?'./.env'),});parsed?=?dotenvResult.parsed;if?(dotenvResult.error)?{throw?error;}}?else?{parsed?=?wxconfig;}//?代碼有省略
}
8.5 支持選擇多個小程序
我們可以用 enquirer[16] 來實現單選或者多選的功能。以下只是關鍵代碼。完整代碼可以查看 mp-cli/src/utils/getConfig.js 文件[17]。
//?只是關鍵代碼
const?{?prompt,?MultiSelect?}?=?require('enquirer');
const?configPathList?=?fs.readdirSync(configPath);
const?configPathListJson?=?configPathList.map((el)?=>?{return?require(`${configPath}/${el}`);
});
const?{?name?}?=?await?prompt({type:?'select',name:?'name',message:?'請選擇一個小程序配置',choices:?configPathListJson,
});
result?=?configPathListJson.filter((el)?=>?el.name?===?name);
return?result;
8.6 支持多個批量上傳
//?只是關鍵代碼
const?{?prompt,?MultiSelect?}?=?require('enquirer');
const?configPathList?=?fs.readdirSync(configPath);
const?configPathListJson?=?configPathList.map((el)?=>?{return?require(`${configPath}/${el}`);
});
const?multiSelectPrompt?=?new?MultiSelect({name:?'value',message:?'可選擇多個小程序配置',limit:?7,choices:?configPathListJson,
});try?{const?answer?=?await?multiSelectPrompt.run();console.log('Answer:',?answer);result?=?configPathListJson.filter((el)?=>answer.includes(el.name),);return?result;
}?catch?(err)?{console.log('您已經取消');console.log(err);process.exit(1);
}
后續可能接入 CI/CD、接入郵件提醒、接入釘釘、支持可視化操作等等
8.7 更多如何使用可以參考文檔
#?克隆我寫的?mp-cli?工具
git?clone?https://github.com/lxchuan12/mp-cli.git
#?克隆騰訊開源的電商小程序
git?clone?https://github.com/lxchuan12/tdesign-miniprogram-starter-retail.git
#?切到分支?feature/release-it
git?checkout?feature/release-it
可以克隆我的項目,到一個目錄中,比如 projects
中。
再克隆我的另外一個小程序(騰訊開源的電商小程序),到同一個目錄中。比如 projects
中。
按照微信小程序文檔[18]配置小程序密鑰等,這樣就能上傳和預覽了。如果沒有微信小程序,可以自行免費開通個人的微信小程序。
9. 總結
通過本文的學習,我們知道了以下知識。
1.?如何利用?release-it?提升版本號,自動打?tag,生成?changelog?等
2.?npm?init?原理
3.?如何寫一個腳手架工具-?如何解析?Nodejs?命令行參數?minimist-?如何選擇單選、多選?enquirer(prompt,?MultiSelect)-?等等
我相信大家也能夠自己動手實現公司類似要求的腳手架工具,減少發版時間,降本提效。
參考資料
[1]
本文提到的工具已開源,可以直接克隆拿去用,也可以自行修改使用,https://github.com/lxchuan12/mp-cli.git,求個star^_^: https://github.com/lxchuan12/mp-cli.git
[2]miniprogram-ci: https://developers.weixin.qq.com/miniprogram/dev/devtools/ci.html
[3]基于 CI 實現微信小程序的持續構建: https://help.coding.net/docs/best-practices/ci/1minute/wechat-mini-program.html
[4]小打卡小程序自動化構建及發布的工程化實踐: https://www.yuque.com/jinxuanzheng/gvhmm5/uy4qu9#8yQ8M
[5]miniprogram-ci 文檔: https://developers.weixin.qq.com/miniprogram/dev/devtools/ci.html
[6]小程序持續集成 @tarojs/plugin-mini-ci: https://taro-docs.jd.com/taro/docs/plugin-mini-ci/
[7]源碼共讀第30期: https://juejin.cn/post/7082662027143053342
[8]release-it 官網倉庫: https://github.com/release-it/release-it
[9]release-it 官網倉庫: https://github.com/release-it/release-it
[10]npm init
: https://docs.npmjs.com/cli/v6/commands/npm-init
create-release-it: https://github.com/release-it/create-release-it
[12]這行源碼位置: https://github.com/release-it/create-release-it/blob/master/index.js#L120
[13]minimist: https://github.com/substack/minimist
[14]kolorist: https://github.com/marvinhagemeister/kolorist
[15]dotenv
: https://github.com/motdotla/dotenv
enquirer: https://github.com/enquirer/enquirer
[17]mp-cli/src/utils/getConfig.js 文件: https://github.com/lxchuan12/mp-cli/blob/main/src/utils/getConfig.js
[18]微信小程序文檔: https://developers.weixin.qq.com/miniprogram/dev/devtools/ci.html
·················?若川簡介?·················
你好,我是若川,畢業于江西高校。現在是一名前端開發“工程師”。寫有《學習源碼整體架構系列》20余篇,在知乎、掘金收獲超百萬閱讀。
從2014年起,每年都會寫一篇年度總結,已經堅持寫了8年,點擊查看年度總結。
同時,最近組織了源碼共讀活動,幫助4000+前端人學會看源碼。公眾號愿景:幫助5年內前端人走向前列。
掃碼加我微信 lxchuan12、拉你進源碼共讀群
今日話題
目前建有江西|湖南|湖北?籍 前端群,想進群的可以加我微信 lxchuan12?進群。分享、收藏、點贊、在看我的文章就是對我最大的支持~