1. 程式人生 > 實用技巧 >Node專案模板管理腳手架ptm-cli開發

Node專案模板管理腳手架ptm-cli開發

目錄

一、ptm-cli 使用說明

  project template manager cli

  一款對專案模板/專案進行管理的腳手架工具,具有新增模板/專案編輯模板/專案刪除模板/專案檢視模板/專案以及下載專案根據模板初始化專案等功能。

1、特點

  • ptm-cli相容githubgitee碼雲

    現在很多自行開發的腳手架都是都只能對github上模板/專案進行下載(底層使用download-git-repo),隨著國內碼雲的發展壯大,國內開發者很多也在碼雲上進行程式碼管理,相容gitee也十分必要;目前現有的腳手架輪子中並沒有相容碼雲的!

  • 管理功能全

    大多數腳手架只對某一個模板進行初始化下載,只具備指定初始化功能;ptm-cli能夠對模板和專案進行管理

    ,不僅可以自由新增刪除開源的優秀專案(例如vue),還可以新增刪除編輯自己開發的專案模板

2、安裝

$ npm install ptm-cli -g

3、使用

1)基礎幫助命令

安裝完在電腦終端輸入相應命令檢視和執行相關操作。

# 檢視腳手架可執行的相關命令語句
$ ptm 

# 檢視當前版本
$ ptm -V

# 檢視幫助
$ ptm -h

2)新增模板/專案

輸入命令:

$ ptm-add

根據終端提示輸入相關資訊:

模板名:新增的模板自定義命名(建議使用引文);

url:模板/專案在github或者碼雲上的https/ssh克隆地址連結;

branch:模板/專案所在github

或者碼雲上的分支名(預設master);

delGitInfo是否刪除模板/專案中的原作者git的開發資訊(預設true刪除),對於模板管理建議預設設定為true,即初始化模板不含有其他讓人的git資訊,對於專案管理(自己專案)建議保留自己開發相關的git資訊;

description:模板/專案的描述資訊(預設為空);

例子:

xxx % ptm-add  
? 請輸入模板名稱 vpblogs
? 請輸入模板地址(https/ssh) [email protected]:goodloving/vpblogs.git
? 請輸入模板分支(預設master) master
? 是否刪除模板中.git資訊(預設刪除) true
? 請輸入模板描述(預設為空) 基於vuepress建立個人部落格主頁的模板工程

新增模板成功!

最終的模板列表為:
   vpblogs
     url:[email protected]:goodloving/vpblogs.git
     branch:master
     description:基於vuepress建立個人部落格主頁的模板工程
     delGitInfo:true
xxx % 

3)編輯模板/專案

輸入命令:

$ ptm-edit templateName key content

根據終端提示輸入相關資訊:

templateName:本人新增過的模板/專案名

key:想要進行編輯的模板/專案的關鍵資訊,包括:urlbranchdelGitInfodescription

content:對關鍵字對應內容進行編輯替代的內容;

例子(修改模板vpblogs的delGitInfo資訊):

xxx % ptm-edit vpblogs delGitInfo false

修改模板成功!

最終的模板列表為:
   vpblogs
     url:[email protected]:goodloving/vpblogs.git
     branch:master
     description:基於vuepress建立個人部落格主頁的模板工程
     delGitInfo:false
xxx % 

4)檢視模板/專案

輸入命令:

$ ptm-list

例子:

xxx % ptm-list

模板列表為:
   vpblogs
     url:[email protected]:goodloving/vpblogs.git
     branch:master
     description:基於vuepress建立個人部落格主頁的模板工程
     delGitInfo:false
xxx % 

5)刪除模板/專案

輸入命令:

$ ptm-del

例子:

xxx % ptm-del
? 請輸入要刪除的模板名稱 vpblogs

刪除模板成功!

最終的模板列表為:
xxx % 

6)基於模板新建/初始化專案

輸入命令:

$ ptm-init vpblogs testPTM

例子(根據模板vpblogs新建專案testPTM):

xxx % ptm-init vpblogs testPTM

開始建立專案~ 

✔ 正在建立中···

專案建立成功~ 

開始你的專案開發!
xxx % 

執行完成後在當前終端所在目錄下可以看到名為testPTM的專案檔案!

ptm-cli 腳手架開發

1、知識儲備

1)commander

完整的 node.js 命令列解決方案,用來處理終端命令列中輸入命令和編寫命令列指令的第三方npm庫。

常用API:

  • 宣告 program 變數

const { program } = require('commander');

  • 命令列輸出版本號

program.version('0.0.1');

  • 命令列輸出指令提示

program.usage("<command> [Options]");

  • 命令列輸出單一命令輸入規範提示

program.command("ptm-add", "新增一個模板庫!")

  • 解析命令列引數

program.parse(process.argv);

  • ···

commander詳細api

2)inquirer

處理可互動的node.js嵌入式的命令列介面的第三方npm庫。

常用API:

  • 宣告 inquirer 變數

const inquirer = require('inquirer');

  • 具體使用方式

inquirer
.prompt([
/* 放入可互動式提供的問題 */
])
.then(answers => {
// 命令列中接收到的輸入引數
})
.catch(error => {
// 報錯獲取
});

  • ···

inquirer詳細api

3)git-clone

通過shell命令克隆一個git儲存庫的第三方npm庫。

常用API:

  • 宣告 git-clone 變數

const clone = require('git-clone');

  • 具體使用方式

clone(repo, targetPath, [options], cb);
克隆一個repo路徑的git倉庫到targetPath目錄下,回撥函式cd用來捕捉克隆結果;

  • options可選引數:
  • git: git的二進位制路徑(可選).
  • shallow: 當為true時克隆深度為1 (可選).
  • checkout: 切換到當前分支(可選).

git-clone詳細api

4)chalk

改變終端輸出樣式的第三方npm庫。

常用API:

  • 宣告 chalk 變數

const chalk = require('chalk');

  • 具體使用方式

console.log(chalk.blue('Hello world!'));

chalk詳細api

5)ora

新增優雅的終端轉輪的第三方npm庫。

常用API:

  • 宣告 ora 變數

const ora = require('ora');

  • 具體使用方式

const spinner = ora('提示內容···');

  • 開始顯示轉輪

spinner.start()

  • 錯誤/失敗顯示轉輪

spinner.fail()

  • 成功轉輪顯示

spinner.succeed()

  • ···

ora詳細api

6)rimraf

封裝rm -rf命令,用來刪除檔案和資料夾的第三方npm庫。

常用API:

  • 宣告 rimraf 變數

const rm = require("rimraf").sync;

  • 具體使用方式,刪除指定file檔案/資料夾

rm(file, [opts], callback)

  • ···

rimraf詳細api

2、初始化專案

  新建專案資料夾PTM_CLI,在專案資料夾下開啟終端執行初始化操作npm init,與終端進行互動操作生成含有專案資訊的package.json檔案,依次安裝步驟1中的6個要用到的第三方npm庫:npm install xxx -g(也可直接將依賴寫入package.json中的dependences中,直接執行npm install);
  開啟package.json檔案,新增終端命令執行語句(bin區域下):

{
  "name": "ptm-cli",
  ···
  "private": false,
  "author": {
    "name": "wawoweb",
    "wechat(公眾號)": "wawoweb  /  哇喔WEB",
    "wechat": "h17179797429",
    "email": "[email protected]"
  },
  "bin": {
    "ptm": "./bin/ptm.js",
    "ptm-init": "./bin/ptm-init.js",
    "ptm-list": "./bin/ptm-list.js",
    "ptm-add": "./bin/ptm-add.js",
    "ptm-del": "./bin/ptm-del.js",
    "ptm-edit": "./bin/ptm-edit.js"
  },
 
  ···
  "dependencies": {
    "chalk": "^4.1.0",
    "commander": "^6.2.1",
    "git-clone": "^0.1.0",
    "inquirer": "^7.3.3",
    "ora": "^5.1.0",
    "rimraf": "^3.0.2"
  }
}

同時,在專案資料夾下新建目錄bin,並在bin資料夾下新建package.json中對應的6個檔案:

./bin/ptm.js         終端命令ptm執行檔案
./bin/ptm-init.js	 終端命令ptm-init執行檔案(根據模板初始化專案)
./bin/ptm-list.js	 終端命令ptm-list執行檔案(檢視當前模板列表)
./bin/ptm-add.js	 終端命令ptm-add執行檔案(新增新的模板)
./bin/ptm-del.js	 終端命令ptm-del執行檔案(刪除指定模板)
./bin/ptm-edit.js	 終端命令ptm-edit執行檔案(編輯指定模板指定資訊內容)

最後在根目錄下新建模板儲存檔案template.json,專案目錄結構如下:

3、功能開發

  在上述新建bin目錄下的6個功能檔案最上方新增#!/usr/bin/env node:配置#!/usr/bin/env node, 就是解決了不同系統node路徑不同,讓系統動態的去查詢node來執行你的指令碼檔案。

1)ptm(腳手架命令提示)

分析:

  當用戶不瞭解ptm-cli時,輸入ptm可以向用戶展示可用的所用命令語句和含義(commander);

程式碼(ptm.js):

#!/usr/bin/env node
const program = require("commander");
const package = require("../package.json");

// 定義當前版本
// 定義使用方法
// 定義五個指令
program
  .version(package.version)
  .usage("<command> [Options]")
  .command("ptm-add", "新增一個模板庫!")
  .command("ptm-del", "刪除一個模板庫!")
  .command("ptm-list", "檢視模板庫列表!")
  .command("ptm-edit templatename key content", "修改模板庫資訊!")
  .command("ptm-init templatename projectName", "基於模板庫建立一個新的工程!");

// 解析命令列引數
program.parse(process.argv);

2)ptm-add(新增模板)

分析:

  將使用者指定模板新增到template.json中儲存起來,需要與使用者進行互動(inquirer),涉及到檔案的讀寫(fs),將執行結果向用戶展示(chalk);

程式碼(ptm-add.js):

#!/usr/bin/env node
//互動式命令列庫
const inquirer = require("inquirer");
//控制檯樣式庫
const chalk = require("chalk");
//node內建檔案模組庫
const fs = require("fs");
//讀取模板配置檔案
const tpConfig = require(`${__dirname}/../template.json`);
// 列印模板列表的公共函式
const printPtmList = require("../utils").printPtmList;

//自定義互動式命令列的問答
let questions = [
  {
    name: "name",
    type: "input",
    message: "請輸入模板名稱",
    validate(val) {
      if (val === "") {
        return "模板名不能為空!";
      } else if (tpConfig[val]) {
        return "模板名已經存在!";
      } else {
        return true;
      }
    },
  },
  {
    name: "url",
    type: "input",
    message: "請輸入模板地址(https/ssh)",
    validate(val) {
      if (val === "") return "模板地址不能為空!";
      return true;
    },
  },
  {
    name: "branch",
    type: "input",
    message: "請輸入模板分支(預設master)",
    default: "master",
  },
  {
    name: "delGitInfo",
    type: "input",
    message: "是否刪除模板中.git資訊(預設刪除)",
    default: true,
  },
  {
    name: "description",
    type: "input",
    message: "請輸入模板描述(預設為空)",
    default: "",
  },
];

inquirer.prompt(questions).then((answers) => {
  // 獲取使用者輸入的內容
  let { name, url, branch, description, delGitInfo } = answers;
  //過濾Unicode的字元
  tpConfig[name] = {
    url,
    branch,
    description,
    delGitInfo,
  };
  // 將模板資訊寫入template.json檔案中s
  fs.writeFile(
    `${__dirname}/../template.json`,
    JSON.stringify(tpConfig),
    "utf-8",
    (err) => {
      if (err) {
        console.log(chalk.red(`\n新增模板失敗:${err}\n`));
      } else {
        console.log(chalk.green("\n新增模板成功!\n"));
        console.log("最終的模板列表為:");
        printPtmList(tpConfig);
      }
    }
  );
});

模板列表列印函式封裝(utils.js):

const chalk = require("chalk");
const printPtmList = (tpConfig) => {
  //遍歷模板展示出來
  for (const key in tpConfig) {
    if (tpConfig.hasOwnProperty(key)) {
      const item = tpConfig[key];
      console.log(chalk.blue(`   ${key}`));
      for (const i in item) {
        if (item.hasOwnProperty.call(item, i)) {
          const el = item[i];
          console.log(chalk.blue(`     ${i}:${el}`));
        }
      }
    }
  }
};
module.exports = {
  printPtmList
};

3)ptm-list、ptm-del、ptm-edit

分析:

  • ptm-list:讀取template.json檔案(fs),對json格式資料輸出列印(chalk);
  • ptm-del:讀取template.json檔案(fs),與使用者互動(inquirer),刪除指定模板資訊,輸出刪除後結果(chalk)
  • ptm-edit:讀取template.json檔案(fs),與使用者互動(inquirer),指定模板的資訊進行修改(commander),輸出最終修改結果(chalk);

程式碼簡單(省略)

4)ptm-init(根據模板初始化專案)

分析:

  提示使用者ptm-init命令必須的引數設定,對輸入引數進行判斷,讀取template.json資訊提取新建專案基於的模板資訊,從github或者gitee(碼雲)clone git庫檔案,根據配置中要求判斷是否刪除原作者的git開發資訊,輸出init結果

程式碼

ptm-init.js

#!/usr/bin/env node
const program = require("commander");
const chalk = require("chalk");
const ora = require("ora");
const gitclone = require("git-clone");
const tpConfig = require(`${__dirname}/../template`);
const rm = require("rimraf").sync;

program.usage("templatename projectName").parse(process.argv);

//判斷輸入情況
if (program.args.length < 1) {
  return program.help();
}
//輸入引數提取
let templateName = program.args[0];
let projectName = program.args[1];
//引數校驗
if (!tpConfig[templateName]) {
  console.log(chalk.red("當前模板不存在!\n"));
  return;
}
if (!projectName) {
  console.log(chalk.red("新建專案名不能為空! \n"));
  return;
}

let temp = tpConfig[templateName];
//提取模板的url
let url = temp.url;
//提取分支
let branch = temp.branch;

console.log(chalk.greenBright("\n開始建立專案~ \n"));
//顯示載入圖示
const spinner = ora("正在建立中···");
spinner.start();

//下載所需額外引數
let cloneOptions = {
  checkout: branch,
  shallow: branch === "master",
};

// 下載git上模板程式碼
gitclone(url, projectName, cloneOptions, (err) => {
  if (err) {
    spinner.fail();
    console.log(chalk.red(`\n建立專案失敗:${err}\n`));
  } else {
    if (temp.deldelGitInfo) {
      // 刪除.git相關檔案
      rm(projectName + "/.git");
    }

    //成功
    spinner.succeed();
    console.log(chalk.green("\n專案建立成功~ \n"));
    console.log(chalk.green("開始你的專案開發!"));
  }
});

4、npm釋出

  • 1)確認package.json中npm釋出內容是否完善正確

    • "name": "ptm-cli", //釋出到npm上的庫的名字
    • "version": "1.0.0", //當前釋出版本號(x.y.z格式規定:x大的版本號,大版本號不同代表不向下相容;y小版本號,當前版本較大改動,向下相容;z程式碼較小改動或者bug修改)
    • "description": "", //npm庫的簡要描述
    • "private": false, //是否公開設定
    • "keywords": [], //npm上搜索的關鍵詞設定
    • ···
  • 2)npm登入和釋出

    • 去npm網站註冊賬號;
    • 終端輸入npm login,根據提示輸入使用者名稱、密碼、郵箱;
    • 終端輸入npm publish 釋出,檢視結果是否釋出成功;
    • 強制撤回24小時內釋出的npm庫,輸入npm unpublish --force
  • 3)npm釋出驗證

    • 在npm網站搜尋中輸入釋出的npm庫名,能夠搜尋到說明已經發布成功!

    • 本地下載驗證

    開啟本地終端輸入npm install ptm-cli -g 下載安裝釋出的npm包,安裝完執行自定義命令有效!