从0-1搭建脚手架

242 阅读6分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第11天,点击查看活动详情

前言

脚手架本质上就是提供模板的工具,在vue中,我们通过npm install -g @vue/cli命令全局安装脚手架,然后执行vue create hello-world就能创建一个项目了,实质上就是通过全局指令,下载了一套webpack模板,让我们可以进行快速开发。我们也可以实现自己的脚手架,在本地上先定义一套webpack模板,然后ctrl+cctrl+v就创建了一个新项目。所以,实现脚手架前提,是需要有一套自定义webpack模板,然后就是如何才能像vue一样,可以通过npm全局安装脚手架,然后通过全局指令,在文件夹中下载webpack模板呢?这篇文章主要介绍如何实现,从npm下载自定义脚手架,本地通过全局指令下载webpack模板。

演示:

  • 全局引入 npm i -g lxj-cli

  • 查看已有模板 go list

  • 创建vue2项目,并配置package.json

  • 查看项目

一、定义本地全局指令

新建index.js

随便创建一个文件夹都行

console.log('666')

然后在当前文件夹的终端输入 node 执行命令

node index.js

但是这样输出又有些不方便,这时就可以尝试在本地定义一个全局的自定义命令。

  1. 初始化 package.json

输入命令后文件夹下会多出一个 package.json 配置文件。

npm init -y

  1. 配置自定义命令

现在在在这个配置文件的最下面添加 bin 选项并自定义一个名叫 go 的指令执行 index.js

  1. 指令连接全局

    输入 link 连接全局后,我们就可以在全局任何地方通过输入 go 命令来运行 index.js

    npm link

    解绑指令:

    npm unlink

    index.js 最上面必须加上这行代码,或者绑定指令之后运行会报错。

    #!/usr/bin/env node

    配置#!/usr/bin/env node, 就是解决了不同的用户node路径不同的问题,可以让系统动态的去查找node来执行你的脚本文件。

    #! 这个符号在Linux或者Unix中叫做:shebang,#!这两个符号就叫shebang

    带有#!就是代表此文件可以当做脚本运行

    /usr/bin/env node这行的意思就是用node来执行此文件,去用户(usr)的安装根目录(bin)下的env环境变量中去找

    如果之前已经设置过link了,必须解绑才能link

二、使用 Commander 解析命令行参数

1. 原生获取命令行参数的方式

使用:process.argv 关键字。

会将路径已数组的形式打印,如果需要加参数,以空格符隔开即可

2. 使用包 Commander.js 模块来获取处理命令行参数

Commander.js 中文文档:

github.com/tj/commande…

Commander文档写的很详细,不会的看文档就行,Commander是一个Nodejs模块,需要在Node环境中运行,在使用前确认一下Node环境是否已安装。

  1. 安装

npm install commander

  1. 安装好后我们可以直接将官网中的示例复制到我们的代码中,然后在控制台输入 go -V 就可以看到控制台已经输出了我们的默认版本号。

    同理,直接输入 go 会弹出选项提示:

#!/usr/bin/env node

const {
  Command
} = require('commander');
const program = new Command();

program
  .name('deploy')
  .version('0.0.1')
  .option('-c, --config <path>', 'set config path', './deploy.conf');

program
  .command('setup [env]')
  .description('run setup commands for all envs')
  .option('-s, --setup_mode <mode>', 'Which setup mode to use', 'normal')
  .action((env, options) => {
    env = env || 'all';
    console.log('read config from %s', program.opts().config);
    console.log('setup for %s env(s) with %s mode', env, options.setup_mode);
  });

program
  .command('exec <script>')
  .alias('ex')
  .description('execute the given remote cmd')
  .option('-e, --exec_mode <mode>', 'Which exec mode to use', 'fast')
  .action((script, options) => {
    console.log('read config from %s', program.opts().config);
    console.log('exec "%s" using %s mode and config %s', script, options.exec_mode, program.opts().config);
  }).addHelpText('after', `
Examples:
  $ deploy exec sequential
  $ deploy exec async`);

program.parse(process.argv);

输入指令:

打印内容:

3. 设计自己的命令行参数

1. init 初始化模板命令

// init 命令
program
  // 定义命令:.command(命令名,[参数])
  // []:表示可选参数
  // <>:表示必填参数
  .command("init <templateName> <projectName>")
  // 命令别名
  .alias("i")
  // 命令作用介绍
  .description("初始化项目模板")
  // 可接在此命令之后连用的指令
  .option("-i, --init <name>", "命令后使用选项接参数示例", "normal")
  // 命令执行回调
  .action((templateName, projectName, options) => {
    // templateName:传给本项命令的参数
    // projectName:传给本项命令的第二个参数
    // options.***:传给命令之后使用的指令的参数(option.init)
    console.log(
      `使用模板名:${templateName}, 项目名称为:${projectName}, ${
        options.init === "normal" ? "" : `选项参数为:${options.init}`
      }`
    );
  });

2. list 查看模板命令

// list 命令
program
  .command("list")
  .description("查看所有可用模板")
  .action(() => {
    console.log(`Webpack Webpack-vue2模板`);
  });

三、进行模板下载

1. 准备模板

  1. 进入 GitHub新建仓库准备好需要使用的模板。

  2. 初始化模板信息

    这里我是在 GitHub 上新建一个仓库,并将自己之前写的一个开发环境上传当做这里的模板进行测试的。

    // 存储模板地址
    const templates = {
      "vue2-cli": {
        // 仓库地址
        url: "https://github.com/liuxueji/vue2-cli.git",
        // 仓库下载地址,格式为:仓库地址:用户名/仓库名#分支名
        downloadUrl: "github:liuxueji/vue2-cli#master",
        description: "Webpack5 + Vue2模板",
      },
    };
    
  3. 修改 go list 命令

    // list 命令
    program
      .command("list")
      .description("查看所有可用模板")
      .action(() => {
        // 遍历模板数组
        for (let i in templates) {
          console.log(`模板名称:${i}`);
          console.log(`模板URL:${templates[i].url}`);
          console.log(`模板介绍:${templates[i].description}`);
        }
      });
    

2. 下载模板(download-git-repo)

自定义模板的好处就是,可以灵活设置项目配置,有时候可能需要一个干净的vue项目,有时候可能需要一个比较完整的vue项目模板,方便进行快速开发。

使用 download-git-repo 下载

NPM 地址:

www.npmjs.com/package/clo…

  1. 安装

npm i download-git-repo

  1. 使用

init 命令中的action回调中设置,接收两个参数:仓库地址和下载路径

  • GitHub
  • GitLab
  • Bitbucket
    // 使用 download-git-repo 下载模板
    // download 第一个参数:仓库地址;第二个参数:下载路径
    const {downloadUrl} = templates[templateName];
    download(downloadUrl, projectName, {
      clone: true
    }, err => {
      if (!err) {
        return console.log("模板创建成功");
      }
    });
  1. 测试
  • 使用前我们需要看看仓库中有哪些模板可以选择(当前只有一个,后续会添加)

  • 根据打印的模板,选择适合的进行下载

  • 此时,就通过全局命令,下载到github仓库中预设置好的模板了,到这里基本功能已经完成。但是模板中的package.json文件是写死的,下面就通过与用户交互,动态创建package.json文件

四、使用 inquirer 和 handlebars 采集处理用户信息

1. 命令行交互 inquirer

能够与用户在命令行进行参数选择交互。

  1. 安装

    npm i inquirer

  2. 使用

    将其放在 download 的下载回调中。

const inquirer = require('inquirer')
inquirer.prompt([
  {
    // 输入类型
    type: "input",
    // 字段名称
    name: "name",
    // 提示信息
    message: "请输入项目名称",
  },
  {
    // 输入类型
    type: "input",
    name: "description",
    message: "请输入项目简介",
  },
  {
    type: "input",
    name: "author",
    message: "请输入作者名称",
  },
])
// 获取输入结果
.then((answers) => {
  console.log(answers.author);
});
  1. 测试
  • 初始化项目并完成与用户交互

  • 成功初始化模板并获取到用户输入信息

  • 接下来,只需要将用户输入的信息写入到package.json中,使用handlebars完成

2. 模板引擎 handlebars

能够读取当前项目下的文件,并重新写入

  1. 安装

npm i handlebars

  1. 修改模板的 package.json

  1. 写入配置文件中

依然使用 fs 模块中的 .writeFileSync() 进行文件写入。

// 导入 handlebars、fs
const handlebars = require('handlebars')
const fs = require("fs");
// 把采集到的用户数据解析替换到 package.json 文件中
// 保存下载下来的模板 package.json 配置文件路径
const packagePath = `${projectName}/package.json`;
// 使用 fs 获取下载到的模板中额 package.json 配置文件
const packageContent = fs.readFileSync(packagePath, "utf8");
// 使用 handlebars 编译这个文件为渲染函数
const packageResult = handlebars.compile(packageContent)(answers);
// 将修改后配置写入下载下来的模板中
fs.writeFileSync(packagePath, packageResult);
console.log("初始化模板成功!");
  1. 测试
  • 初始化模板,并设置项目名、项目简介、作者名称

  • 项目package.json中信息成功修改

五、npm 发包

  1. npm官网注册一个账号

  2. NPM 搜索看有无重名包。

  3. package.json 中的 name 修改为发布到 npm上的包名。

  4. 打开控制台,执行登录命令:npm login

  5. 登陆成功以后,在项目下执行发布命令:npm publish

  6. 解绑全局命令:npm unlink

  7. 发布成功,在本地进行安装

    npm i lxj-cli
    
  8. 安装完毕,使用go命令进行测试

    go list
    go init vue2-cli project1
    

总结:

脚手架的意义是快速构建项目,提高我们的开发效率。对我来说,每次做一个项目,都要重新配置一次webpack,特别难受。所以,我自定义脚手架的目的,就是希望能制作一个开箱即用的模板,能不配置就不配置,而且还有利于统一每个项目结构,百利无一害🤗。所以,最重要的就是如何配置一个开箱即用的webpack模板了。