前端如何搭建一個簡單的腳手架

Yoki發表於2019-03-18

前言

這裡先簡單瞭解一下基礎知識,接下來會基於typescript和rollup參考寫一個較為完整的腳手架(動態模板),以下只能拉取較為簡單的靜態模板。

基礎

腳手架釋出和安裝

這裡假設我們的腳手架名字是ds-cli,以下都用這個名字。我們在命令列使用腳手架命令為ds

  • 我們怎麼樣讓使用者通過npm或者yarn全域性安裝ds-cli之後,在終端能執行ds命令呢?答案就在package.json的bin欄位
  • 當我們bin欄位指向我們的目標檔案main.js,同時目標檔案開頭具有
//這裡是main.js
#!/usr/bin/env node

// --這種用法是為了防止作業系統使用者沒有將node裝在預設的/usr/bin路徑裡。當系統看到這一行的時候,
// 首先會到env設定裡查詢node的安裝路徑,再呼叫對應路徑下的直譯器程式完成操作。
//這裡是package.json
"bin": {
    "ds": "./main.js"
}
複製程式碼
  • 這樣當我們釋出上npm,別人下載下來後,就可以直接使用ds命令了。

解析命令列

  • 如何輕鬆便捷的讀取命令列裡的引數呢?這裡我們使用tj大神的commander
const cmd = require("commander");

// 比如我們想執行ds init **的命令,想出現“初始化元件模板”的描述
// action是執行這個命令後續的回撥,...args是後面**的引數
cmd
  .command('init')
  .description('初始化元件模板')
  .action((...args) => {});

//解析命令列
cmd.parse(process.argv);
複製程式碼

使用者互動

我們通過詢問使用者來獲得一定的互動,這樣可以知道使用者需要什麼

  • 採用inquirer詢問專案描述,作者
//比如我們在上面那個action裡面搞事情,即ds init之後問使用者
...action((...args)=>{
    inquirer
      .prompt([
        {
          name: "description",
          message: "請輸入專案描述"
        },
        {
          name: "author",
          message: "請輸入作者名稱"
        }
      ]).then(answers=>{
          //在這裡獲得上面的答案
          console.log(answers.description,answers.author)
      })
})
複製程式碼

拉取遠端的倉庫

const download = require("download-git-repo");
// 第一個git地址,第二個name是git clone下來後的名字...
download(
    "https://github.com/yokiyokiyoki/vue-fullpage.git#master",
    name,
    { clone: true },
    err => {
    ...
    }
);
複製程式碼

簡單的模板替換

  • 我們通過詢問互動後,肯定內部做了些改變。這裡我們可以把package.json的作者和描述簡單改了
  • 可以使用handlebars,模板語法簡單
//這個是通過download-git-repo拉下來的package.json
{
    "author":"{{author}}",
    "description":"{{description}}"
}
複製程式碼
  • 然後我們通過讀取檔案字串給handbars編譯一下拿到的變數,再寫入
//通過詢問拿到的answers
const meta = {
    name,
    description: answers.description,
    author: answers.author
};
const fileName = `${name}/package.json`;
//判斷一下是否有這個檔案
if (fs.existsSync(fileName)) {
    const content = fs.readFileSync(fileName).toString();
    const result = handlebars.compile(content)(meta);
    fs.writeFileSync(fileName, result);
}
複製程式碼

終端的一些效果

  • 高亮終端列印出來的資訊:chalk。如chalk.green('成功了'),chalk.red('失敗了')
  • 終端載入效果:ora,有個loading效果
    前端如何搭建一個簡單的腳手架
const spinner = ora("正在下載模板...");
spinner.start();
spinner.succeed();
複製程式碼

前端如何搭建一個簡單的腳手架

原始碼

#!/usr/bin/env node
// --這種用法是為了防止作業系統使用者沒有將node裝在預設的/usr/bin路徑裡。當系統看到這一行的時候,
// 首先會到env設定裡查詢node的安裝路徑,再呼叫對應路徑下的直譯器程式完成操作。
const program = require("commander");
const download = require("download-git-repo");
const inquirer = require("inquirer");
const handlebars = require("handlebars");
const fs = require("fs");
const ora = require("ora");
const chalk = require("chalk");
const symbols = require("log-symbols");

program
  .version("0.0.1", "-v, --version")
  .command("init <name>")
  .action(name => {
    if (fs.existsSync(name)) {
      // 錯誤提示專案已存在,避免覆蓋原有專案
      console.log(symbols.error, chalk.red("專案已存在"));
      return;
    }
    inquirer
      .prompt([
        {
          name: "description",
          message: "請輸入專案描述"
        },
        {
          name: "author",
          message: "請輸入作者名稱"
        }
      ])
      .then(answers => {
        download(
          "https://git.datatub.com:Uranus/general-template#master",
          name,
          { clone: true },
          err => {
            const spinner = ora("正在下載模板...");
            spinner.start();
            if (!err) {
              spinner.succeed();
              const meta = {
                name,
                description: answers.description,
                author: answers.author
              };
              const fileName = `${name}/package.json`;
              if (fs.existsSync(fileName)) {
                const content = fs.readFileSync(fileName).toString();
                const result = handlebars.compile(content)(meta);
                fs.writeFileSync(fileName, result);
              }
              console.log(symbols.success, chalk.green("專案初始化完成"));
            } else {
              spinner.fail();
              console.log(symbols.error, chalk.red(`拉取遠端倉庫失敗${err}`));
            }
          }
        );
      });
  });
//解析命令列
program.parse(process.argv);

複製程式碼
  • 上面是main.js檔案,然後修改一下package.json的欄位(bin欄位修改,模板變數)
  • 釋出npm(如何釋出,請參考這裡),自己通過npm全域性下載之後體驗一下

下篇

前端如何搭建一個成熟的腳手架

相關文章