Vue-cli打造自己項(xiàng)目的腳手架工具

Vue-cli打造自己項(xiàng)目的腳手架工具

為什么需要腳手架(命令行工具)?

  • 減少重復(fù)性的工作,不再需要復(fù)制其他項(xiàng)目再刪除無關(guān)代碼,或者從零創(chuàng)建一個(gè)項(xiàng)目和文件;
  • 根據(jù)交互動(dòng)態(tài)生成項(xiàng)目結(jié)構(gòu)和配置文件等;
  • 多人協(xié)作更為方便,不需要再把文件傳來傳去。

實(shí)現(xiàn)思路

image.png
  • 項(xiàng)目模板放在github上
  • 用戶通過命令交互的方式下載不同的模板
  • 經(jīng)過模板引擎渲染定制項(xiàng)目模板
  • 模板變動(dòng),只需要更新模板即可,不需要用戶更新腳手架

涉及知識(shí)點(diǎn)及模塊

  • NodeJs
    基于Node.js開發(fā)命令行工具
  • ECMAScript 6
    使用最新版本語言進(jìn)行開發(fā)
  • npm 發(fā)包
    npm包的發(fā)布及更新流程
  • commander.js
    可以自動(dòng)的解析命令和參數(shù),用于處理用戶輸入的命令
  • download-git-repo
    下載并提取git倉庫,用于下載項(xiàng)目模板
  • Inquirer.js
    通用的命令行用戶界面集合,用于和用戶進(jìn)行交互
  • handlebars.js
    模板引擎,將用戶提交的信息動(dòng)態(tài)填充到文件中
  • ora
    下載過程久的話。可以用于顯示下載中的動(dòng)畫效果
  • chalk
    可以給終端的字體加上顏色
  • log-symbols
    可以在終端上顯示出狗√或×等圖標(biāo)

初始化操作

  • 初始化
mkdir demo-cli
cd demo-cli
npm init -y // 初始化生成package.json文件
  • 新建 index.js 并寫入以下內(nèi)容:
#!/usr/bin/env node

console.log('hello cli');
  • 配置package.json 中的bin字段
{
  "name": "vue-cli-test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "bin": {
    "test": "index.js"
  }
}
  • 執(zhí)行npm link 鏈接命令到全局/執(zhí)行npm unlink 可以建命令移除(在項(xiàng)目根路勁下執(zhí)行)
  • 執(zhí)行bin中配置的命令測(cè)試
    例如:在命令行輸入命令 test 可看到對(duì)應(yīng)輸出。

命令行工具參數(shù)設(shè)計(jì)

test -h|--help   // 查看使用幫助
test -V|--version   // 查看工具的版本號(hào)
test list   // 列出所有可用模板
test init <template-name> <project-name>  // 基于指定的模板進(jìn)行項(xiàng)目初始化

使用 commander 模塊處理命令行

  • 安裝
    npm install commander
  • 使用
#!/usr/bin/env node
// 使用Node開發(fā)命令行工具所執(zhí)行的Javascript腳本必須在頂部加入 #!/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 logSymbols = require('log-symbols')
// 1.獲取用戶輸入命令
// process.argv原生獲取命令行參數(shù)的方式
// console.log(process.argv)
program
    .version('0.0.1') // -V 或者 --version 的時(shí)候輸出該版本號(hào)
const templates = {
    'tpl-a': {
        url: '', // 模板倉庫地址
        downloadUrl: 'http://github.com:用戶名/倉庫名#分支名', // 模板下載地址
        description: 'a模板',
    },
    'tpl-b': {
        url: '',
        downloadUrl: '', // 模板下載地址
        description: 'b模板',
    },
    'tpl-c': {
        url: '',
        downloadUrl: '', // 模板下載地址
        description: 'c模板',
    }
}
program
    .command('init <template> <project>')
    .description('初始化項(xiàng)目模板')
    .action((templateName, projectName) => {
        const spiner = ora('正在下載模板...').start()
        // 根據(jù)模板名下載對(duì)應(yīng)的模板到本地
        // download: 第一個(gè)參數(shù)是倉庫下載地址,第二個(gè)參數(shù)是下載路勁
        const {downloadUrl} = templates[templateName];
        download(downloadUrl, projectName, {clone: true}, (err) => {
            if (err) {
                spiner.fail();
                console.log(logSymbols.error, chalk.red('初始化模板失敗'))
                return
            }
            spiner.succeed(); // 下載成功提示
            // 模板文件下載成功
            // 1. 把項(xiàng)目下的package.json文件讀取出來
            // 2. 使用向?qū)У姆绞讲杉脩糨斎氲闹?            // 3. 使用模板引擎把用戶輸入的數(shù)據(jù)解析到package.json文件中
            // 4. 解析完畢,把解析之后的結(jié)果重新寫入package.json文件中
            inquirer.prompt([
                {
                    type: 'input',
                    name: 'name',
                    message: '請(qǐng)輸入項(xiàng)目名稱'
                },
                {
                    type: 'input',
                    name: 'description',
                    message: '請(qǐng)輸入項(xiàng)目名稱'
                },
                {
                    type: 'input',
                    name: 'author',
                    message: '請(qǐng)輸入項(xiàng)目名稱'
                }
            ]).then((answers) => {
                // 把采集到的用戶輸入的數(shù)據(jù)解析替換到package.json中
                const packagePath = `${projectName}/package.json`
                const packageContent = fs.readFileSync(packagePath, 'utf8') // 讀取本地文件
                const packageResult = handlebars.compile(packageContent)(answers) // 編譯替換
                fs.writeFileSync(packagePath, packageResult); // 重寫到本地文件
                console.log(logSymbols.success, chalk.yellow('初始化模板成功'))
            })
        })
    });
program
    .command('list')
    .description('查看所有可用模板')
    .action(() => {
        for (key in templates) {
            console.log(`${key} ${templates[key].description}`)
        }
    })
program.parse(process.argv);
// 2. 根據(jù)不同的指令執(zhí)行不同的功能操作

image.png

下載模板

  • 安裝
    npm install download-git-repo
  • 修改代碼


    image.png
  • download()第一個(gè)參數(shù)就是倉庫下載地址
    端口號(hào)后面的'/' 在參數(shù)里要寫成‘:’
    #master 代表的就是分支名
    不同的模板可以放在不同的分支下,更改分支便可以實(shí)現(xiàn)下載不同的模板文件了
  • 第二個(gè)參數(shù)是路勁
    上面我們直接在當(dāng)前路徑下創(chuàng)建一個(gè)name命名的文件夾存放模板,也可以使用二級(jí)目錄比如test/${name}

命令行交互

  • inquirer
    一組常見的交互式命令行用戶界面。
  • 安裝
    npm install inquirer

命令行交互功能可以在用戶執(zhí)行init命令后,向用戶提出問題,接收用戶的輸入并做出相應(yīng)的處理,這里使用inquirer.js來實(shí)現(xiàn)。


image.png

1)問題就放在prompt()中
2)問題的類型為input就是輸入類型
3)name就是作為答案對(duì)象中的key
4)message就是問題了
5)用戶輸入的答案就在answers中
修改模板內(nèi)package.json文件里需要用戶自定義配置的參數(shù),例如:


image.png

在下載模板完成后將用戶輸入的答案渲染到package.json中
  • handlebars(模板引擎)
    Handlebars.js 是Chris Wanstrath 創(chuàng)建的Mustache 模板語言的擴(kuò)展。
  • 安裝
    npm i handlebars
// 把采集到的用戶輸入的數(shù)據(jù)解析替換到package.json中const packagePath = `${projectName}/package.json`
onst packageContent = fs.readFileSync(packagePath, 'utf8') // 讀取本地文件const packageResult = handlebars.compile(packageContent)(answers) // 編譯替換
fs.writeFileSync(packagePath, packageResult); // 重寫到本地文件

上面使用node.js的文件模塊fs,將handlebars渲染完成后的模板重新寫入到文件中。

視覺美化

在用戶輸入答案后,開始下載模板,這時(shí)候使用ora來提示用戶正在下載中。

  • 安裝ora
    npm install ora
image.png

然后通過chalk來為打印信息加上樣式,比如成功信息為綠色,失敗信息為紅色,這樣子會(huì)讓用戶更加容易分解,同時(shí)也讓終端的顯示更加的好看。

  • 安裝chalk
    npm install ora
  • 安裝log-symbols
    npm install log-symbols

npm 發(fā)包

發(fā)完包之后就能通過npm下載自己的cli
npm install --global 腳手架名

  1. 打開npmjs.com官網(wǎng)
  2. 注冊(cè)一個(gè)npm賬號(hào)
  3. 在npm檢索是否有重名的包名
  4. 將package.json里的name修改為發(fā)布到npm上的包名(該名字和本地項(xiàng)目名稱無關(guān))
  5. 打開控制臺(tái),執(zhí)行npm login,登錄npm
  6. 登錄成功以后,在項(xiàng)目下執(zhí)行 npm publish 發(fā)布
  7. 發(fā)布成功,就可以在本地進(jìn)行安裝測(cè)試了
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容