面試官:請簡述一下vue-cli命令列工具,你能自己手寫一個嗎?

xlei1123發表於2018-07-13

還記得我們在寫vue 專案的時候用腳手架vue-init的主要作用是根據指定模板生成專案原型嘛?那麼vue-init怎麼實現的呢? 其實就是在vue-cli package.json中增加下面的程式碼

{
  "bin": {
    "vue": "bin/vue",
    "vue-init": "bin/vue-init",   //執行vue-init 的時候下載專案原型
    "vue-list": "bin/vue-list",
    "vue-build": "bin/vue-build"
  }
}

複製程式碼

具體實現請看下面:

本篇的主要內容是:實現可以在命令列中,直接執行程式碼(下面的名字可以自己取)。

xl-cli install (安裝)
複製程式碼

在實現自己的命令列執行程式碼前,你需要對命令列,npm(包管理器)的基本用法有些瞭解。 下面進入正題:

//建立一個 xl-cli資料夾 mkdir xl-cli
// cd xl-cli 
// npm init  初始化
複製程式碼

完成上面幾個步驟之後 我們能看到生成了一個xl-cli資料夾 檔案中包含一個package.json檔案。

{
  "name": "xl-cli",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}
複製程式碼

我們知道在npm run xxx的時候其實就是執行的package.json中的scripts,比如上面 你看看npm run test就會輸出Error: no test specified,我們的程式碼用的es6需要編譯成es5,先建立一個npm run compile,(test沒用,同時給test刪掉)

{
  "name": "xl-cli",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "compile": "babel src -d dist"
  },
  "author": "",
  "license": "ISC"
}
複製程式碼

我們需要安裝babel 建立 (安裝babel-cli babel-env)

src 
    --main.js
複製程式碼

這個時候我們執行 npm run compile其實就是相當於在命令列中輸入了 babel src -d dist 然後我們看到了生成了一個這樣的目錄:

dist
    --main.js
複製程式碼

我們經常會有這樣的需求就是在更改src 裡面的內容的時候 同步更改dist裡面的內容,可以這樣做:在package.json的scripts增加一個 watch命令:

{
  "name": "xl-cli",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "compile": "babel src -d dist",
    "watch":"npm run compile -- --watch"
  },
  "author": "",
  "license": "ISC"
}
複製程式碼

然後執行 npm run watch命令 就實現了同步更新了!

下面實現 xl-cli命令列

建立 ./bin/www目錄, 要實現在命令列中使用 類似vue-cli這樣的命令 需要在package.json中增加

"bin": {
    "xl-cli": "./bin/www"
  },
複製程式碼

./bin/www中的內容:

#! /usr/bin/env node

require('../dist/main.js');
複製程式碼

第一行 最後的node是表示node環境 前面引數寫死的,第二行表示執行的程式碼 ,建立完成後執行npm link,相當於在本地新增環境變數。 至此,你已經可以執行xl-cli命令了,其實就是執行了dist/main.js。

實現像其他命令列中的xl-cli --help 先引入一個包 commander ,這個包可以幫助我們設定和解析命令引數。 src/main.js

//main.js
import program from 'commander';

import {VERSION} from './utils/constants';

program.command('install')                            //加命令 
        .description('install template')
        .alias('i')
        .action(() => {
            console.log('使用者install了')
        })

program.version(VERSION,'-v --version').parse(process.argv);  //加 option
複製程式碼

我們可以看到在命令視窗輸入 xl-cli install 會列印出:

使用者install了
複製程式碼

好了 到現在我們就剩下執行下載模板任務了,這樣我們新建一個install.js來執行下載任務

//install.js
import ora from 'ora';   //ora 一個命令列loading效果
import inquirer from 'inquirer'  //命令列互動
import downLoadGit from 'download-git-repo';  //github api用來下載github的模板

let install = async () => {
    // 下載模板 
    let loading = ora('fetching template......');
    let answer = await inquirer.prompt([
        {
            type: 'input',        //你可以輸入你自己的名稱
            name: 'projectName',
            message:'專案名稱',
            default:'xlDemo'    //預設名
        }
    ]);
    // 專案名字
    let project = answer.projectName;
    loading.start();
    //我在github上面上傳了一個非常簡單的模板 xlei1123/xl-cli downLoadGit(src, dest)  從哪拉 拉到那  process.cwd()+'/'+project這是拉到了當前目錄下的你剛剛命名的檔案中
    downLoadGit('xlei1123/xl-cli',process.cwd()+'/'+project,(err) => {  
        if(err) {
            console.log(err)
            return;
        }
        console.log(process.cwd()+'/'+project)
        loading.succeed();
    });
}
export default install;
複製程式碼

這樣在上面的action中執行 install()就好了!

//main.js
import program from 'commander';
import {VERSION} from './utils/constants';

import install from './install'
program.command('install')                            //加命令 
        .description('install template')
        .alias('i')
        .action(() => {
            install()
        })

program.version(VERSION,'-v --version').parse(process.argv);  //加 option
複製程式碼

這樣我們就完成了自己cli了,可以執行下面幾個簡單的命令看一下效果:

xl-cli --help
xl-cli -v
xl-cli install
複製程式碼

一句話總結:我們釋出了一個npm包 這個包的package.json中有bin可以全域性執行,判斷引數有install,就從github上面拉取模板。

當然這篇實現的是簡單的命令列工具主要是理解其中大致原理,肯定會存在很多不足的地方,歡迎各位提出寶貴的意見或建議,也希望能幫助到你從中獲得一些知識!

相關文章