前言
本文介紹使用 Node 做一個腳手架,便於快速開發專案。我們開發的是腳手架,而非專案,目前本人只有一個腳手架—— Koa 腳手架 ,後續寫到 React、webpack 時,會搭建屬於自己的一套 H5 端的開發模板。本文以實現最小腳手架為出發點展開寫作,後續也會在此基礎上添磚加瓦
引子
A:大 B 哥,Node 能做什麼?
B:搭建 Web 服務嚕
A:不僅如此,它還能作業系統
B:怎麼說?
A:知道 Webpack 嗎?它就是用 Node 寫的。還有像 create-react-app、 vue-cli、@tarojs/cli 這些,都是用 Node 寫的,這些 cli 被稱為腳手架,你只要使用一些命令就能下載模板快速開發
B:(各種羨慕、吹捧後),我也想做一套自己的腳手架
A:我教你啊
一個腳手架的思路
看 create-react-app、 vue-cli、@tarojs/cli 的各自的倉庫,我們能得出一些共同點,例如多套模板、友好的互動、優美的 UI 等等。我們這裡以 taro 為例,先用用,看看,再仿著做一個
它是怎麼做到選擇不同的模板,能生成不同的檔案呢?明明只有一個基礎模板啊,選擇 scss 就生成 scss 檔案,選擇 TypeScript 生成 TS 檔案,現在還看不懂原始碼,以後寫完 webpack 再來看看,我們這裡只先做一個最簡單的腳手架
建立工程
mkdir azhu-cli
cd azhu-cli
npm init -y
然後在 package.json 中寫點專案資訊
需要安裝的 npm 包
我們先列個表格,檢視一下各個 npm 包是什麼,有什麼用,後續在寫程式碼時一步步新增進去
包名稱 | 說明 |
---|---|
commander | 執行復雜的命令 |
inquirer | 問答互動 |
download-git-repo | 下載遠端模板 |
chalk | 讓你 console.log 出來的字帶顏色,比如成功時的綠色字 |
ora | loading |
建立一個命令
先建立 index.js
,在程式碼中寫入
#!/usr/bin/env node
console.log('hello world')
在終端中執行 node 程式,輸入 node 命令
node index.js
可以正確輸出 hello world
,程式碼頂部的 #!/usr/bin/env node
是告訴終端,這個檔案要使用 node 去執行
一般 cli 都有一個特定的命令,例如 taro
,git
等,我們設定我們的命令—— azhu
。如何讓終端識別這個命令呢?很簡單,在 package.json 檔案中新增一個欄位 bin
,並且宣告一個命令關鍵字和對應執行的檔案:
# package.json
...
"bin": {
"azhu": "index.js"
}
...
然後我們測試一番,在終端中輸入 azhu
,會提示:
為什麼會這樣呢?通常我們在使用 cli 工具時,都需要先安裝它,比如 vue-cli,@tarojs/cli,使用前需要全域性安裝:
npm i vue-cli -g
npm i @tarojs/cli -g
而我們的 azhu-cli 並沒有釋出到 npm 上,當然也沒有安裝過,所以終端現在還不認識這個命令。通常我們想本地測試一個 npm 包,可以使用 npm link
這個命令,本地安裝這個包,我們執行一下:
npm link
再執行 azhu
命令,就看到 hello world
了
注:npm unlink 解除安裝本地包
執行復雜的命令
commander:處理命令列互動
- 自帶了 -V,-h 互動
- 可以通過
program.command
新增互動 program.parse
將命令引數傳入 commander 管道中,一般放在最後執行
npm i commander --save
改造 index.js
#!/usr/bin/env node
const program = require('commander')
const package = require('./package.json')
program.version(package.version)
program.parse(process.argv)
執行 azhu -h
新增問答操作
inquirer 新增問答操作
npm i inquirer --save
語法很簡單,直接看程式碼:
inquirer
.prompt([
{ type: 'input', message: '請輸入專案名稱', name: 'name' },
{
type: 'list',
message: '請選擇專案模板',
name: 'template',
choices: ['koa-basic'],
},
])
.then((answers) => {
console.log('answers', answers)
})
每個選項中的 name 為答案輸出的值
克隆模板
download-git-repo
- 下載遠端模板
npm i download-git-repo --save
原本使用 shelljs,但是死活下載不下來,只能選擇另一個工具
當我們下載寫好專案名字,選擇好模板後,下一步就要從遠端倉庫上把模板下載過來
.then((answers) => {
console.log('正在拷貝專案,請稍等')
const remote = 'https://github.com:johanazhu/koa-basic#master'
const tarName = answers.name
download(remote, tarName, { clone: true }, function (err) {
if (err) {
console.log(err)
} else {
console.log('成功')
}
})
})
新增 UI 互動
有時候下載遠端倉庫時會花很多時間,我們必須為了體驗,需要加一些 UI 效果優化體驗
chalk & ora
npm i chalk ora --save
chalk 是給 console 加顏色
ora 是加 loading 效果的
...
.then((answers) => {
console.log('正在拷貝專案,請稍等')
const remote = 'https://github.com:johanazhu/koa-basic#master'
const tarName = answers.name
+ const spinner = ora('download template......').start()
download(remote, tarName, { clone: true }, function (err) {
if (err) {
+ console.log(chalk.red(err))
spinner.fail()
} else {
+ console.log(chalk.green('成功'))
spinner.succeed()
}
})
})
效果如下:
釋出 npm
先登入 npm,再發布
npm login...npm publish
額外知識點
包管理方式
monorepo
- 將多個專案程式碼儲存在一個倉庫裡的軟體開發策略
- 把所有的專案相關都放在一個倉庫(比如 React,Babel,Umi,Taro)
- 集中管理
優勢
- 統一工作流
- 降低基建成本
- 提高團隊協作效率
劣勢
- 體積問題
- 許可權問題
- 版本控制
multirepo
- 按模組放在為多個倉庫(webpack、rollup)
優勢
- 靈活
- 安全
劣勢
- 程式碼複用
- 版本管理
- 開發除錯
- 搭建基礎架構
大的專案可以使用 monorepo,獨立性比較強的可以採用 multirepo
我個人更喜歡 multirepo 的哲學
有人上升到哲學層面,其實俺覺得不同的專案應採用合適自己的管理方式,像 webpack、rollup 之類,專案獨立性比較強,就可以用使用 multirepo ,而像 React,Umi,Taro 之類的框架,它首先要拆分功能點,其次每個子庫之間需要與主庫有所依賴,如果採用 multirepo 方式,關聯起來會很麻煩,採用統一管理的方式能節省很多時間
常見問題
一:使用 shelljs
常有報錯,暫時解決不了,所以用 download-git-repo
這種方式
fatal: unable to access 'https://github.com/johanazhu/koa-basic/': OpenSSL SSL_read: Connection was reset, errno 10054
解決方案
開啟 Git 命令頁面,執行 git 命令指令碼:修改設定,解除 ssl 驗證
git config --global http.sslVerify "false"
注:git config --list 檢視你的 config 資訊
二:download-git-repo
報錯誤
'git clone' failed with status 128
解決方案:https://github.com/wuqiong7/Note/issues/17
我將 remote 地址改成:https://github.com:johanazhu/koa-basic#master 就好了
Github 已釋出:https://github.com/johanazhu/azhu-cli