Node 開發npm腳手架(類似vue-cli)

Node 開發npm腳手架(類似vue-cli)

npm install tengyu-cli -g

源碼已經上傳碼雲:https://gitee.com/bingtengaoyu/tengyu_cli.git

一.構建腳手架思路

  1. 構建腳手架的目的

    爲了快速構建項目,修改配置信息,達到自動化前端工程的目的

  2. 思路:兩種方式

    第一種方式:從GitHub拉取代碼,修改配置,需要在GitHub提供一個可供下載的模板,完成初始化,下載後解壓zip包,然後刪除zip包,修改配置文件,配置代理,下載依賴,啓動項目;

     

    第二種方式:將壓縮後的zip模板放到服務器上,腳手架從服務器下載對應的模板,根據提示輸入配置信息,完成初始化,下載後解壓zip包,然後刪除zip包,修改配置文件,配置代理,下載依賴,啓動項目

二. 初始化項目

npm init

三. 修改package.json入口文件

{
  "name": "tengyu-cli",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",  // 入口文件
  "bin": {
    "tengyu": "index.js"
  },
  "scripts": {
    "serve": "node index.js",
    "dev": "node index.js",
    "start": "node index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "gengbingbing",
  "license": "ISC",
  "dependencies": {
    "chalk": "^3.0.0",
    "commander": "^4.1.1",
    "cross-spawn": "^7.0.1",
    "download-git-repo": "^3.0.2",
    "handlebars": "^4.7.3",
    "inquirer": "^7.0.4",
    "log-symbols": "^3.0.0",
    "ora": "^4.0.3",
    "request": "^2.88.2"
  }
}

四. 下載依賴

npm install 

五. 開始編寫腳手架(直接上源碼)

index.js

#!/usr/bin/env node
​
const program = require('commander');       //設計命令行
const download = require('download-git-repo');      //github倉庫下載
const inquirer = require('inquirer');       //命令行答詢
const handlebars = require('handlebars');       //修改字符
const ora = require('ora');         //命令行中加載狀態標識
const chalk = require('chalk');     //命令行輸出字符顏色
const logSymbols = require('log-symbols');      //命令行輸出符號
const fs = require('fs');
const request = require('request');
const { resolve } = require("path");
const install = require("./utils/install");
​
console.log(chalk.green(`
                           tengyu cli 命令
    ------------------------------------------------------------
       tengyu init <template name> projectName  |  初始化項目 
       tengyu -V                                |  查看版本號    
       tengyu -h                                |  查看幫助      
       tengyu list                              |  查看模板列表  
       tengyu download                          |  下載zip模板  
    ------------------------------------------------------------
`));
// 可用模板
const templates = {
    'react-npm-template': {
        url: 'https://gitee.com/bingtengaoyu/reactAntd',
        downloadUrl: 'https://gitee.com:bingtengaoyu/reactAntd#master',
        description: 'react基礎模板'
    },
    'vue-tools': {
        url: 'https://gitee.com/bingtengaoyu/vueTools',
        downloadUrl: 'https://gitee.com:bingtengaoyu/vueTools#master',
        description: 'vue常用組件'
    }
}
​
// tengyu -V|--version
program.version('1.0.0');  // -v|--version時輸出版本號0.1.0
​
// tengyu init <template> <project>
program
    .command('init <template> <project>')
    .description('初始化項目模板')
    .action((templateName, projectName) => {
        console.log(templateName, templates);
        let downloadUrl = templates[templateName].downloadUrl;
        //下載github項目,下載牆loading提示
        const spinner = ora('正在下載模板...').start();
        //第一個參數是github倉庫地址,第二個參數是創建的項目目錄名,第三個參數是clone
        download(downloadUrl, projectName, { clone: true }, err => {
            if (err) {
                console.log(logSymbols.error, chalk.red('項目模板下載失敗\n   只能下載list列表中有的模板'));
                console.log(err);
            } else {
                spinner.succeed('項目模板下載成功');
                //命令行答詢
                inquirer.prompt([
                    {
                        type: 'input',
                        name: 'appid',
                        message: '請輸入appid',
                        default: ''
                    },
                    {
                        type: 'input',
                        name: 'name',
                        message: '請輸入項目名稱',
                        default: projectName
                    },
                    {
                        type: 'input',
                        name: 'description',
                        message: '請輸入項目簡介',
                        default: ''
                    },
                    {
                        type: 'input',
                        name: 'author',
                        message: '請輸入作者名稱',
                        default: ''
                    }
                ]).then(answers => {
                    //根據命令行答詢結果修改package.json文件
                    let packsgeContent = fs.readFileSync(`${projectName}/package.json`, 'utf8');
                    let packageResult = handlebars.compile(packsgeContent)(answers);
                    fs.writeFileSync(`${projectName}/package.json`, packageResult);
                    console.log(packageResult)
                    fs.writeFileSync(`${projectName}/config.js`, `module.exports = ${JSON.stringify(answers)}`);
​
                    console.log(logSymbols.success, chalk.green('項目初始化成功,開始下載依賴...'));
​
                    install({ cwd: `${resolve('./')}/${projectName}` }).then(data => {
                        console.log(logSymbols.success, chalk.green('項目依賴下載成功!'));
                    });
​
                    //用chalk和log-symbols改變命令行輸出樣式
                })
            }
        })
    })
​
// 下載zip模板
program
    .command('download')
    .description('初始化項目模板')
    .action((templateName, projectName) => {
        inquirer.prompt([
            {
                type: 'input',
                name: 'project_name',
                message: '請輸入項目名稱',
                default: 'tengyu-template'
            },
            {
                type: 'list',
                name: 'template_name',
                message: '請選擇需要下載的模板',
                choices: [
                    'react快速開發模板',
                    'vue工具集'
                ],
                default: 'react-npm-template'
            }
        ]).then(answers => {
            let url = ''
            switch (answers.template_name) {
                case 'react快速開發模板':
                    url = templates['react-npm-template'].url;
                    break;
                case 'vue工具集':
                    url = templates['vue-tools'].url;
                    break;
                default:
                    url = templates['react-npm-template'].url
            }
​
            function downloadFile(uri, fileName, callback) {
                var stream = fs.createWriteStream(fileName);
                request(uri).pipe(stream).on('close', callback);
            }
​
            downloadFile(url, `${answers.project_name}.zip`, function () {
                console.log(logSymbols.success, chalk.green(`${answers.template_name}下載完畢!`));
                return
            });
        })
    })
​
// tengyu list
program
    .command('list')
    .description('查看所有可用模板')
    .action(() => {
        console.log(chalk.green(`
                              tengyu 模板
            -----------------------------------------------
                 react-npm-template   react快速開發模板  
                 vue-tools            vue工具集
            -----------------------------------------------
        `))
    })
​
program.parse(process.argv);

util-install.js文件(用於下載依賴)

使用cross-spawn模塊進行自定義cmd命令的編寫

const spawn = require("cross-spawn");
​
module.exports = function install(options) {
    const cwd = options.cwd || process.cwd();
    return new Promise((resolve, reject) => {
        const command = options.isYarn ? "yarn" : "npm";
        const args = ["install", "--save", "--save-exact", "--loglevel", "error"];
        const child = spawn(command, args, { cwd, stdio: ["pipe", process.stdout, process.stderr] });
​
        child.once("close", code => {
            if (code !== 0) {
                reject({
                    command: `${command} ${args.join(" ")}`
                });
                return;
            }
            resolve();
        });
        child.once("error", reject);
    });
};

至此一個簡單的腳手架已經開發完成

npm link之後即可在本地進行試運行了

六. 發佈npm庫

  1. 設置自己的npm代理,不要設置爲了淘寶代理等;

  2. 去npm註冊自己的賬號;

  3. 上傳自己的npm腳手架

    npm login // 登錄
    ​
    npm publish // 推送自己的腳手架到npm庫
  4. 大功告成,可以下載自己的npm插件了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章