前端工程化实战:脚手架直播-笔记

103 阅读4分钟

本节主要是自己搭一款像caz、vue那样的脚手架,了解搭建脚手架需要哪些知识和工具。

准备工作

对于node脚本文件我们都要在文件顶部添加这样一行代码:#! /usr/bin/env node,它最终要做的事情就是找到当前环境里的 node.exe 程序,然后将它做为解析器来执行当前 cli.js

经常会遇到cli命令无法执行问题,这时候一般要检查该cli文件的权限,在目标文件夹下通过ls -l命令可以查看文件权限,通过chmod命令可以修改文件权限。一般是使用chmod  755  文件名.后缀

读取参数

我们在全局变量process.argv中,可以拿到执行该cli命令时的参数,它默认有两个参数,代表的是:当前解析器在哪(此处是node)、该全局命令所对应文件在哪

[ '/usr/local/bin/node', '/usr/local/bin/bcli' ]

对于后面接的参数,它会拼在数组后。

像vue那样,我们需要做一个默认的帮助信息打印,我们可以通过自定义编码来实现帮助信息的格式化处理,也可以用第三方包,比如commander、yargs

commander的使用

使用commander的各类API来完成我们的需求,

const { program } = require('commander')

// commander定义方法示例
program
    .command("create")
    .alias("crt")
    .description("创建一个项目")
    .action(()=>{
        console.log("执行该命令指定操作");
    })

// 将cli 参数交给commander去解析,执行对应的任务
program.parse(process.argv)

分发命令

index.js只负责分发命令,有不同的模块文件去执行。

命令行及美化操作

inquirer、ora与chalk的使用

ora及chalk使用示例

const ora = require("ora");
const chalk = require("chalk");

module.exports = function (params) {
    const spinner = ora("正在下载......")
    spinner.start();
    setTimeout(() => {
        console.log(chalk.green('create操作完成了'))
        spinner.fail(chalk.red('失败'))
        spinner.succeed(chalk.greenBright('下载成功了'))
        spinner.info('信息')

        // chalk的使用
        // 背景颜色
        console.log(chalk.bgBlueBright(chalk.red('看看这是啥')));
        // 段落输出
        console.log(chalk`
            {green 疑是长河落九天}
            {red 举杯望明月}
        `);
      }, 2000)
}

inquirer使用示例

基本使用、递进问题处理、钩子函数的使用:

const inquirer = require('inquirer');
const chalk = require('chalk');

const quesList = [
  {
    type: "input",
    name: "userName",
    message: "请输入您的姓名",
    default: chalk.grey("zcc"),
  },
  {
    type: "input",
    name: "userPhone",
    message: "请输入您的电话号码",
    validate(val) {
        if(!val){
            return '此处为必填'
        } else {
            return true
        }
    }
  },
  {
    type: "checkbox",
    name: "userConfig",
    message: "请选择您的配置",
    pageSize: 3, // 一页展示几项
    choices: ['react', 'vue', 'webpack', 'gulp', 'vuex', 'redux', 'mobx']
  },
  {
      type: "confirm",
      name: "isInstall",
      message: "是否按照依赖"
  },
  {
      type: "list",
      name: "methods",
      message: "请选择下载工具",
      choices: ["npm", "cnpm", "yarn"],
      when(is) {
        if(is.isInstall) {
            return true;
        } else {
            return false;
        }
      }
  },
]

module.exports = function () {
  inquirer.prompt(quesList).then((answer) => {
    console.log(answer);
  })
}

问题类型

list、input、confirm、checkbox

钩子函数

validate、when

常见属性

type、name、choices、message、default

模板下载

我们的模板一般放在gitgub或者是gitlab上,可以通过以下链接进行下载:

// 获取组织仓库列表信息
https://api.github.com/orgs/lagoufed/repos

// 获取个人仓库列表信息
https://api.github.com/users/zcegg/repos

// 获取指定仓库版本号
https://api.github.com/repos/zcegg/create-nm/tags

通过axios访问api:

const axios = require('axios');

module.exports = async function (params) {
    let ret = await axios('https://api.github.com/users/zcegg/repos').catch(err => console.log(err));
}

解决访问限制

通过获取git仓库的token,然后在访问API时,将token加入请求头中,就能达到每小时5000次

下载Git仓库

我们可以借助download-git-repo这个库完成git仓库下载。同时我们要做一个缓存目录,它既可以用于数据渲染,也可以进行模板缓存,当远端模板没变化时,可以直接使用本地缓存。

获取本地缓存路径

`${process.env[process.platform === 'win32' ? 'USERPROFILE' : "HOME"]}/.tmp`

资源拷贝

可以通过第三方包ncp直接拷贝资源到指定目录

数据渲染

使用第三方包metalsmith来进行数据渲染,这里使用的是ejs模板语言,所以需要一个把ejs填充到模板里的功能,这里使用consolidate这个第三方包。

将这些包都装为安装依赖,然后开始写metalSmith部分的逻辑:

await new Promise((resolve, reject) => {
  // 这里默认要传一个__dirname,不然会报错
  MetalSmith(__dirname)
    .source(dest)
    .destination(path.resolve(...proname))
    .use((files, metal, done) => {
    console.log(files)
    done()
  })
    .use((files, metal, done) => {
    done()
  })
    .build((err) => {
    err ? reject(err) : resolve()
  })
})

source是指定资源在哪;destination是指定资源所要拷贝的目录;use是使用插件,来进行数据渲染的操作;build是执行以上操作。其用法类似于gulp的pipe流式操作,但其并不是数据流模式。

use所传入的函数,它会将资源中的每一个文件都递归遍历一次,每个文件以如下形式输出,文件名为键,文件信息为值:

'package.json': {
  contents: <Buffer 7b 0a 20 20 22 6e 61 6d 65 22 3a 20 22 68 65 6c 6c 6f 31 22 2c 0a 20 20 22 76 65 72 73 69 6f 6e 22 3a 20 22 30 2e 31 2e 30 22 2c 0a 20 20 22 73 63 72 ... 904 more bytes>,
  mode: '0644',
  stats: Stats {
  dev: 16777221,
  mode: 33188,
  nlink: 1,
  uid: 501,
  gid: 20,
  rdev: 0,
  blksize: 4096,
  ino: 50307596,
  size: 954,
  blocks: 8,
  atimeMs: 1618372377993,
  mtimeMs: 1600293756000,
  ctimeMs: 1618372378007.7263,
  birthtimeMs: 1600293756000,
  atime: 2021-04-14T03:52:57.993Z,
  mtime: 2020-09-16T22:02:36.000Z,
  ctime: 2021-04-14T03:52:58.008Z,
  birthtime: 2020-09-16T22:02:36.000Z
}

文件内容以buffer形式进行了储存