• 项目脚手架搭建 cli js


    脚手架功能模块图

    脚手架流程图

    安装lerna

    lerna是一个可以在管理多个npm包,所以对于多个npm包管理很方便。

    npm install lerna -g
    

    建立项目文件夹

    mkdir xi-cli
    cd xi-cli
    mkdir command
    mkdir core
    mkdir utils
    

    lerna初始化

    lerna init
    

    npm包主要是分功能放在command、core、utils三个文件下面,所以需要删除packages,修改lerna.json

     "packages": ["command/*", "core/*", "utils/*"]
    

    实现个模块功能

    添加core模块

    lerna create @xi-cli/core
    


    给core/index.js 添加#!usr/bin/env node,让系统执行xi-cl的时候,去环境变量里面去找node来执行

    // core/index.js
    #!usr/bin/env node
    //core/package.json
    "bin": {
        "xi-cli": "lib/index.js"
      },
    

    执行npm link

    npm link
    

    测试命令

    xi-cli
    

    添加日志模块

    //添加日志
    lerna create @xi-cli/log
    //安装npmlog
    lerna add npmlog --scope=@xi-cli/log
    

    在log/index.js里面,初始化npmlog的基本配置

    "use strict";
    const npmlog = require("npmlog");
    //定义npmlog的level
    npmlog.level = process.env.LOG_LEVEL ? process.env.LOG_LEVEL : "info";
    npmlog.heading = "xi-cli";
    module.exports = npmlog;
    

    core模块功能开发

    core模块主要实现init项目命令

    //给core模块添加 log模块
    lerna add @xi-cli/log --scope=@xi-cli/core
    

    安装commander

    lerna add commander --scope=@xi-cli/core
    

    注册init命令

    program
        .name("xi-cli")
        .command("init [name]")
        .option("-f,--force", "是否强制初始化项目")
        .action((name) => {
         console.log("name")
        });
     //重点 不能忘记
      program.parse(process.argv);
    

    测试命令

    xi-cli init projectname
    

    实现init项目command的逻辑

    这里主要实现的功能就是下载模板,render模板,安装依赖,启动项目这几项功能

    "use strict";
    
    const fs = require("fs");
    const inquier = require("inquirer");
    const fse = require("fs-extra");
    const {execSync} = require("child_process");
    const path = require("path");
    const glob = require("glob");
    const ejs = require("ejs");
    const log = require("@xi-cli/log");
    const {resolve} = require("path");
    //__dirname 执行文件的目录  这里是init/lib/index.js
    //需要的程序执行的当前目录
    const localPath = process.cwd();
    class Init {
      constructor(name) {
        this.propjectName = name;
        this.force = true;
        this.configInfo = {
          projectName: name,
        };
        this.exec();
      }
      async exec() {
        try {
          // 准备阶段
          await this.prepare();
          //下载模块
          this.downloadTemplate();
          //匹配文件
          let files = await this.getGlobFile();
          //ejsrender模板
          let res = await this.ejsRender(files);
          let tempalteDir = await this.moveFile();
          //删除模板文件夹
          fse.removeSync(path.join(localPath, tempalteDir));
          //安装依赖 并启动
          this.installDepend();
          this.initStartProject();
        } catch (e) {
          log.error(e);
        }
      }
      async prepare() {
        //判断当前目录是否为空
        if (this.isCewEmpty()) {
          //询问是否创建
          const answer = await inquier.prompt([
            {
              type: "confrim",
              name: "isContinue",
              message: "当前文件不为空,是否继续?",
              default: "xi-project",
            },
          ]);
          if (answer.isContinue) {
            //是否启动强制更新
            fse.emptyDirSync(localPath);
          }
        }
      }
      isCewEmpty() {
        let fileList = fs.readdirSync(localPath);
        //文件过滤
        fileList = fileList.filter((file) => {
          return !file.startsWith(".") && ["node_modules"].indexOf(file) < 0;
        });
        return fileList.length > 0 && fileList ? true : false;
      }
      downloadTemplate() {
        log.info("开始下载模板");
        //git模块的地址
        execSync("git clone https://gitee.com/rainbowChenhong/xi-template.git", {
          stdio: [0, 1, 2], // we need this so node will print the command output
          cwd: localPath, // path to where you want to save the file
        });
      }
      async getGlobFile() {
        const dir = process.cwd();
        return new Promise((resolve, reject) => {
          glob(
            "**",
            {
              cwd: dir,
              //忽略文件
              ignore: ["**/**.html"],
              //匹配文件夹
              nodir: true,
            },
            (err, files) => {
              if (err) reject(err);
              resolve(files);
            }
          );
        });
      }
      ejsRender(files) {
        let filesPromise = [];
        files.map((file) => {
          const filePath = path.join(localPath, file);
          filesPromise.push(
            new Promise((resolve, reject) => {
              ejs.renderFile(filePath, this.configInfo, (err, result) => {
                if (err) {
                  reject(err);
                }
                if (result) {
                  //写入
                  fse.writeFileSync(filePath, result);
                }
                resolve(result);
              });
            })
          );
        });
        return Promise.all(filesPromise);
      }
      moveFile() {
        return new Promise((resolve, reject) => {
          glob(
            "**",
            {
              cwd: localPath,
              //忽略文件
              ignore: [],
              //匹配文件夹
              nodir: true,
            },
            (err, files) => {
              let curentDir = "";
              files.map((file) => {
                if (err) reject(err);
                const filePath = path.join(localPath, file);
                let fileAr = file.split("/");
                curentDir = fileAr.shift();
                let newPath = path.join(localPath, fileAr.join("/"));
                //移动文件
                fse.moveSync(filePath, newPath);
              });
              resolve(curentDir);
            }
          );
        });
      }
      installDepend() {
        execSync("npm install ", {
          stdio: [0, 1, 2],
          cwd: localPath,
        });
      }
      initStartProject() {
        execSync("npm run start ", {
          stdio: [0, 1, 2],
          cwd: localPath,
        });
      }
    }
    module.exports = Init;
    

    修改core/lib/index.js

    //安装init模块
    lerna add @xi-cli/init --scope=@xi-cli/core
    //core/lib/index.js 修改命令
    const Init = require("@xi-cli/init");
     program
        .command("init [name]")
        .option("-f,--force", "是否强制初始化项目")
        .action((name) => {
          new Init(name);
        });
    

    测试执行

    //需要注意的是不支持 windows 系统
    //因为内部是使用#!/usr/bin/env node 来执行命令的
    xi-cli init projectName
    //windows系统
    node core/lib/index.js init projectname
    

    效果:

    代码地址

  • 相关阅读:
    mysql中IN和EXITS效率
    POJ 3301 Texas Trip
    Swift项目兼容Objective-C问题汇总
    使用linq对字符串1,2,3,4,5,6,7,8,9,10求和
    CodeForces 228D. Zigzag(线段树暴力)
    代理模式
    Oracle成长点点滴滴(3)— 权限管理
    数据结构基础 之 图 的 邻接矩阵实现与邻接表实现
    android CoordinatorLayout使用
    Android开发之蓝牙(Bluetooth)操作(二)--修改本机蓝牙设备的可见性,并扫描周围可用的蓝牙设备
  • 原文地址:https://www.cnblogs.com/heihei-haha/p/14697669.html
Copyright © 2020-2023  润新知