github地址:github.com/jinxuanzhen… 以爲有用的朋友幫忙給項目一個star,謝謝javascript
接上文 《從0到1開發一個小程序cli腳手架(一)--建立頁面/組件模版篇》html
上文你們應該大體學會了怎麼搭建一個cli腳手架,包括實現了一個快速生成啓動模版的功能,本質上做爲腳手架應該能夠作更多的事情,本篇文章會實現一些新的功能,例如:自動發佈體驗版,版本號控制,環境變量控制java
不知道你們有沒有一天發屢次版本或者一天給多個小程序發版的經歷,按照微信正常的發佈流程,須要:node
其中全部的1,2步爲手工修改config文件,第5步是確認手工修改config文件的正確性,畢竟人總會犯錯,做者表示就幹過線下環境發佈到測試環境的事情,並且這是在作了第5步的狀況下,很遺憾沒有仔細覈對webpack
爲了避免再次發生一樣的事情致使引咎辭職,那麼有沒有更好的方法呢 ?天然是有的,既然人不可靠,那麼直接把它流程化天然就能夠了git
最好閱讀了上篇文章《從0到1開發一個小程序cli腳手架(一)--建立頁面/組件模版篇》,並搭建了一個簡單的demogithub
須要瞭解微信小程序提供的一些cli能力, 點擊這裏web
後續的不少流程上的實操代碼爲了縮短篇幅會以僞代碼的形式來進行描述,強烈推薦先閱讀上文,若是須要更詳細的實操代碼請去github倉庫查看json
實際效果圖:
gulp
是否是發現很是簡單,事實也是如此,整個功能作下來也就60行代碼 ~
項目結構分爲入口文件,配置文件
- lib
- publish-weapp.js
- index.js
- config.js
- node_modules
- package.json
複製代碼
config.js用來記錄一些基礎常量和默認項的配置,例如項目路徑,執行路徑等
module.exports = {
// 根目錄
root: __dirname,
// 執行命令目錄路徑
dir_root: process.cwd(),
// 小程序項目路徑
entry: './',
// 項目編譯輸出文件夾
output: './',
}
複製代碼
在入口文件(index.js)處利用第三方庫 commander 識別命令行參數,同時做爲路由進行任務分發,
#!/usr/bin/env node
const version = require('./package').version; // 版本號
/* = package import -------------------------------------------------------------- */
const program = require('commander'); // 命令行解析
/* = task events -------------------------------------------------------------- */
const publishWeApp = require('./lib/publish-weapp'); // 發佈體驗版
program
.command('publish')
.description('發佈微信小程序體驗版')
.action((cmd, options) => publishWeApp();
/* = main entrance -------------------------------------------------------------- */
program.parse(process.argv)
複製代碼
接下來是一個QA環節,這時候須要根據本身的實際須要安排本身須要的命令,能夠回想一下要解決的問題:
大概得出這樣一個隊列:
function getQuestion({version, versionDesc} = {}) {
return [
// 肯定是否發佈正式版
{
type: 'confirm',
name: 'isRelease',
message: '是否爲正式發佈版本?',
default: true
},
// 設置版本號
{
type: 'list',
name: 'version',
message: `設置上傳的版本號 (當前版本號: ${version}):`,
default: 1,
choices: getVersionChoices(version),
filter(opts) {
if (opts === 'no change') {
return version;
}
return opts.split(': ')[1];
},
when(answer) {
return !!answer.isRelease
}
},
// 設置上傳描述
{
type: 'input',
name: 'versionDesc',
message: `寫一個簡單的介紹來描述這個版本的改動過:`,
default: versionDesc
},
]
}
複製代碼
最後得到的json對象,是這個樣子:
{isRelease: true, version: '1.0.1', versionDesc: '這是一個體驗版'}
複製代碼
主要是由於體驗版並不是徹底是發行版,公司內部測試的時候也是須要發佈測試用體驗版的,可是又涉及只有正式版本修改本地版本文件,那麼就只能多此一問做爲區分了
設置上述如圖的 體驗版上的版本號和描述信息,
這裏有個case是隻有第一個問題選擇發佈正式版纔會讓你設置版本號,測試版本使用默認版本號0.0.0,這也是區分體驗版的一種方式
when(answer) {
return !!answer.isRelease
}
複製代碼
這裏只設置了三個問題:是否發佈正式版,設置版本號,設置上傳描述,固然你也能夠設置本身想作的其餘事情
翻了下小程序的文檔,大概猶以下幾個關鍵點:
小程序cli並不是全局安裝,須要本身去索引路徑,命令行工具所在位置:
macOS: <安裝路徑>/Contents/MacOS/cli
Windows: <安裝路徑>/cli.bat
mac的 安裝路徑 若是是默認安裝的話,是/Applications/wechatwebdevtools.app/, 外加cli的位置是:
/Applications/wechatwebdevtools.app/Contents/Resources/app.nw/bin/cli
windows 的話做者表示沒有這個環境,只能你們本身探索了
官方文檔給了很是詳細的描述:
# 上傳路徑 /Users/username/demo 下的項目,指定版本號爲 1.0.0,版本備註爲 initial release
cli -u 1.0.0@/Users/username/demo --upload-desc 'initial release'
# 上傳並將代碼包大小等信息存入 /Users/username/info.json
cli -u 1.0.0@/Users/username/demo --upload-desc 'initial release' --upload-info-output /Users/username/info.json
複製代碼
基本流程:
獲取cli -> 獲取當前版本配置 -> 問題隊列(獲取上傳信息)-> 執行上傳(cli命令)-> 修改本地版本文件 -> 成功提示
// ./lib/publish-weapp.js 文件
module.exports = async function(userConf) {
// cli路徑
const cli = `/Applications/wechatwebdevtools.app/Contents/Resources/app.nw/bin/cli`;
// 版本配置文件路徑
const versionConfPath = Config.dir_root + '/xdk.version.json';
// 獲取版本配置
const versionConf = require(versionConfPath);
// 開始執行問題隊列 anser case: {isRelease: true, version: '1.0.1', versionDesc: '這是一個體驗版'}
let answer = await inquirer.prompt(getQuestion(versionConf));
versionConf.version = answer.version || '0.0.0';
versionConf.versionDesc = answer.versionDesc;
//上傳體驗版
let res = spawn.sync(cli, ['-u', `${versionConf.version}@${Config.output}`, '--upload-desc', versionConf.versionDesc], { stdio: 'inherit' });
if (res.status !== 0) process.exit(1);
// 修改本地版本文件 (當爲發行版時)
!!answer.isRelease && await rewriteLocalVersionFile(versionConfPath, versionConf);
// success tips
Log.success(`上傳體驗版成功, 登陸微信公衆平臺 https://mp.weixin.qq.com 獲取體驗版二維碼`);
}
// 修改本地版本文件
function rewriteLocalVersionFile(filepath, versionConf) {
return new Promise((resolve, reject) => {
fs.writeFile(filepath, jsonFormat(versionConf), err => {
if(err){
Log.error(err);
process.exit(1);
}else {
resolve();
}
})
})
}
複製代碼
注意這裏須要在項目根目錄下建立一個xdk.version.json的版本文件,詳細配置說明見倉庫
大體是這樣的結構:
// xdk.version.json
{
"version": "0.12.2",
"versionDesc": "12.2版本"
}
複製代碼
到這裏基本就完成了上傳的全部步驟,能夠當前項目下鍵入xdk-cli publish
查看一下程序是否正常運行,注意上傳出錯記得檢查是否處於登陸狀態
能夠看到在版本號環節使用的是list類型,而非input類型,這是由於手寫版本號有寫錯的風險, 仍是讓我作選擇題吧 emmm...
最終效果:
就不在這裏展開了,能夠下, 搜索getVersionChoices
函數:
github.com/jinxuanzhen…
你會發現是運行cli命令就直接發佈了,那麼用gulp,webpack等工具項目由於須要上傳dist目錄而非src的緣由,須要先進行打包再進行發佈: gulp -> xdk-cli publish ,將一個動做拆成了兩個
遺忘了一個怎麼辦?糾結了
不知道你們對微信開發者工具的上傳鉤子還有沒有印象,要實現的大概就是這麼個東西,
一個上傳前預處理的鉤子
這個實現起來也很簡單,首先給用戶的配置文件(xdk.config.js)開一個可配置項:
// xdk.config.js
{
// 發佈鉤子
publishHook: {
async before(answer) {
this.spawnSync('gulp');
return Promise.resolve();
},
async after(answer) {
this.log('發佈後的鉤子執行了~');
return Promise.resolve();
}
}
}
複製代碼
在publish-weapp.js中去識別鉤子便可:
// 前置鉤子函數
await userConf.publishHook.before.call(originPrototype, answer);
//上傳體驗版
let res = spawn.sync(cli, ['-u', `${versionConf.version}@${Config.output}`, '--upload-desc', versionConf.versionDesc], { stdio: 'inherit' });
// 後置鉤子函數
await userConf.publishHook.after.call(originPrototype, answer);
複製代碼
固然,你須要判斷下鉤子是否存在,類型判斷,包括須要返回給用戶配置裏一些基本的方法和屬性,例如:日誌輸出,命令行執行等
我這邊以gulp爲例,能夠看到在publsih前先執行gulp
,後進行發佈,最後log出一行提示信息
徹底符合預期
解決了自動上傳的問題,接下來就要解決環境變量切換的問題了,這裏還要借用下剛纔寫的鉤子函數:
{
// 發佈鉤子
publishHook: {
async before(answer) {
this.spawnSync('gulp', [`--env=${answer.isRelease ? 'online' : 'stage'}`]);
return Promise.resolve();
},
async after(answer) {
this.log.success('發佈後的鉤子執行了~');
return Promise.resolve();
}
}
}
複製代碼
以gulp爲例,根據以前的回答的結果answer.isRelease,判斷是否爲使用正式環境
若是你沒有使用編譯工具,也能夠提出一個env的config文件,使用fs模塊直接重寫該環境變量
下面是一串僞代碼:
目錄結構
- app (小程序項目)
- page
- app.json
...
- env.js
- xdk.config.js
- xdk.version.js
- envConf.js
// envConf.js
module.exports = {
['online']: {
appHost1: 'https://app.xxxxxxxxx.com',
appHost2: 'https://app.xxxxxxxxx.com',
},
['stage']: {
appHost1: 'https://stage.xxxxxxxxx.com',
appHost2: 'https://stage.xxxxxxxxx.com',
}
};
// xdk.config.js
publishHook: {
async before(answer) {
let config = require('envConf.js')[answer.isRelease ? 'online' : 'stage'];
fs.writeFile('./app/env.js', jsonFormat(jsonConf), (err) => {
if(err){
this.log.error('寫入失敗')
}else {
this.log.success('寫入成功);
}
});
return Promise.resolve();
}
複製代碼
打包工具的問題還有環境變量的問題,我都沒有寫在cli裏面,是由於不一樣項目之間對環境變量的寫法,格式都不盡相同,具體要怎麼作仍是要留給開發者本身來肯定吧,這樣看起來更靈活一些
總之利用腳手架解決了從發佈到上線的一連串問題,使得再也不擔憂由於切換環境致使線上bug,也再也不擔憂寫版本號寫錯的問題,確認線上環境這個環境也變成了一個非強需求的事情
整個上線流程也只須要:xdk-cli publish -> 提交審覈便可,並且整個代碼也並不複雜,publish-weapp.js整個文件算上註釋也就60行代碼,何樂不爲呢?
注:下篇會講一下如何作自定義指令,幫助小夥伴能夠更自由的適配不一樣的項目~