用 Node 搭建最小實現腳手架

山頭人漢波發表於2022-04-13

前言

本文介紹使用 Node 做一個腳手架,便於快速開發專案。我們開發的是腳手架,而非專案,目前本人只有一個腳手架—— Koa 腳手架 ,後續寫到 React、webpack 時,會搭建屬於自己的一套 H5 端的開發模板。本文以實現最小腳手架為出發點展開寫作,後續也會在此基礎上添磚加瓦

引子

A:大 B 哥,Node 能做什麼?

B:搭建 Web 服務嚕

A:不僅如此,它還能作業系統

B:怎麼說?

A:知道 Webpack 嗎?它就是用 Node 寫的。還有像 create-react-appvue-cli@tarojs/cli 這些,都是用 Node 寫的,這些 cli 被稱為腳手架,你只要使用一些命令就能下載模板快速開發

B:(各種羨慕、吹捧後),我也想做一套自己的腳手架

A:我教你啊

一個腳手架的思路

create-react-appvue-cli@tarojs/cli 的各自的倉庫,我們能得出一些共同點,例如多套模板、友好的互動、優美的 UI 等等。我們這裡以 taro 為例,先用用,看看,再仿著做一個

使用Taro-cli建立專案

它是怎麼做到選擇不同的模板,能生成不同的檔案呢?明明只有一個基礎模板啊,選擇 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 出來的字帶顏色,比如成功時的綠色字
oraloading

建立一個命令

先建立 index.js,在程式碼中寫入

#!/usr/bin/env node
console.log('hello world')

在終端中執行 node 程式,輸入 node 命令

node index.js

可以正確輸出 hello world ,程式碼頂部的 #!/usr/bin/env node 是告訴終端,這個檔案要使用 node 去執行

一般 cli 都有一個特定的命令,例如 tarogit 等,我們設定我們的命令—— azhu。如何讓終端識別這個命令呢?很簡單,在 package.json 檔案中新增一個欄位 bin,並且宣告一個命令關鍵字和對應執行的檔案:

# package.json
...
"bin": {
    "azhu": "index.js"
}
...

然後我們測試一番,在終端中輸入 azhu,會提示:

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

commander處理

新增問答操作

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 為答案輸出的值

inquirer

克隆模板

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()
        }
    })
})

效果如下:

chalk&ora

釋出 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

參考資料

相關文章