搭建一个NodeJS脚手架

前端脚手架搭建分享


最近团队需要统一脚手架,花了点时间了解了一下如何去进行搭建
其实原理并不复杂,

第一步,首先我们要知道需要哪些东西,然后我们要创建什么东西

  1. 我们首先需要一个可被 node 执行入口文件

  2. 需要生成文件的模板

  3. 使用 node fs 模块把模板写入我们指定的目录

这是最简单的思路,那么我们就可以动手了

  1. 首先创建一个文件夹,然后在文件夹执行 npm init 初始化一个 package.json 文件

  2. 然后创建一个入口文件 index.js,然后写入

    #!/usr/bin/env node
    
    console.log('hello,cli!');
    复制代码

    这时候执行 node index.js 就能够在控制台打印 hello,cil!

  3. 再创建一个模板文件 template.js, 添加字符串

    hello,template!
    复制代码
  4. 然后我们在 index.js 进行修改,通过 process.cwd()获取 node 当前执行路径,我们可以读取一个文件,并写入到一个目录下

    #!/usr/bin/env node
    
    console.log('hello,cli!');
    
    const fs = require("fs");
    const path = require("path");
    
    const folderName = path.join(process.cwd(), "/cli");
    
    // 判断文件夹是否存在
    const mkdirFile = (name) => {
    try {
        if (!fs.existsSync(name)) {
        fs.mkdirSync(name);
        }
    } catch (err) {
        console.error(err);
    }
    };
    
    fs.readFile("./template.js", "utf-8", (err, data) => {
    if (err) {
        console.log(err);
        return;
    } else {
        console.log(data);
        mkdirFile(folderName);
        fs.writeFileSync(`${folderName}/template.js`, data);
    }
    });
    
    复制代码
  5. 第一步基础就完成了。下面我们进行思考

    如何在创建脚手架时,需要在控制台进行交互,这时候需要引入安装第三方库

    • commander 可以自动的解析命令和参数,用于处理用户输入的命令
    • inquirer 用户输入/选择交互
    • ora 控制台进度动画提示

    好了,这时候我们修改 index.js,执行 node index.js 就会提示,使用 create 参数,执行 node index.js create 项目名,然后进入项目类型选择,选择完成,就会创建对应名称的项目文件夹,并在里面创建 template.js

#!/usr/bin/env node

// console.log("hello,cli!");

const fs = require("fs");
const path = require("path");
const ora = require("ora");
const inquirer = require("inquirer");
const program = require("commander");

// 判断文件夹是否存在
const mkdirFile = (name) => {
  try {
    if (!fs.existsSync(name)) {
      fs.mkdirSync(name);
    }
  } catch (err) {
    console.error(err);
  }
};

const doFs = (name) => {
  fs.readFile("./template.js", "utf-8", (err, data) => {
    if (err) {
      console.log(err);
      return;
    } else {
      mkdirFile(name);
      fs.writeFileSync(`${name}/template.js`, data);
    }
  });
};

program
  //   .version('1.0.0')
  .command("create <app-name>")
  .description("create a new project")
  .action(async (name) => {
    const cwd = process.cwd();

    const questions = [
      {
        type: "list",
        message: "请选择项目类型: ",
        name: "type",
        choices: [{ name: "web项目", value: "web" }],
      },
    ];
    const { type } = await inquirer.prompt(questions);

    const proce = ora("Start creating...");
    proce.start();
    const folderName = path.join(cwd, name);
    doFs(folderName);
    proce.succeed("succeed done!");
  });

program.parse(process.argv);

复制代码

那么到此,我们的基本思路已经完成,我们需要重新整理一下。

  • 首先,我们创建一个 bin 文件夹,添加 tara.js 文件,作为我们的入口,在其中引入 index.js

  • 创建一个 src 文件夹,里面存放我们所有的源码,添加 src/core 文件夹

  • 因为后续的模板定义,类定义会用到,我们需要可直接执行 ts 文件,所以需要添加一个第三方组件,npm i -S ts-node @types/node,具体使用可以参照官方文档,然后将 tara.js 改造

#!/usr/bin/env node

const tsNode = require("ts-node/dist/bin");
const path = require("path");

(async () => {
    const argv = process.argv.slice(2);
    const dir = path.join(__dirname, "../src");
    tsNode.main(["index.ts", ...argv], { "--dir": dir });
})();

复制代码
  • 修改 index.js 为 index.ts,并给所有方法参数添加类型定义,然后直接执行 node bin/tara,这时候会抛 Cannot find module ‘typescript’错误,需要安装 ts 库 npm i -S typescript

  • 这时候我们也可以使用远程模板 download-git-repo 支持从 Github 下载仓库,详细了解可以参考官方文档。

npm install --save download-git-repo
复制代码

download() 第一个参数就是仓库地址,详细了解可以看官方文档

  • 使用本地模板,那我们的思路是,可以生成一个统一的模板配置对象,然后根据配置,一个一个的生成文件,从而生成完整的项目目录

    • 那第一步就是先创建一个模板类 Project.ts,定义生成 package.json 文件的属性

      _init_方法是一个抽象方法,用于子类进行自定义一些操作

        import Package from "./Package";
    
        abstract class Project {
            name: string;
            private package: Package;
    
            constructor(parameters) {}
    
    
            init() {}
    
            protected abstract _init_: void;
        }
    
        export default Project;
    复制代码
    • 创建一个 Package 类
    class Package {
        constructor(parameters) {}
    }
    
    export default Package;
    复制代码

// TODO

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享