likes
comments
collection
share

脚手架开发流程

作者站长头像
站长
· 阅读数 14

本文作者为360公司奇舞团团队前端工程师韩国芳。

目前日常工作中常用的脚手架有 vue-cli、create-react-app、angular-cli 等等,都是通过简单的初始化命令,完成内容的快速构建。 脚手架是我们经常用到的可以提效的工具,经常用在一些代码重复性高的项目中,开发者通过输入命令行、回答问题,就能快速生成一套代码,来避免手动编写。下面我们就来了解脚手架的构建流程和必备工具。

1. 搭建框架

1.1 新建cli目录

mkdir my-cli && cd my-cli // 创建仓库目录
npm init // 初始化 package.json

1.2 新建bin文件夹,添加main.js

mkdir bin && cd bin && touch main.js

编辑main.js文件:

#! /usr/bin/env node

console.log('my-cli start')
#! /usr/bin/env node 作用:

#! 是为了指定脚本的解释程序,可是不同用户或者不同的脚本解释器有可能安装在不同的目录下,系统如何知道要去哪里找你的解释程序呢? **/usr/bin/env **就是告诉系统可以在PATH目录中查找。 所以配置#!/usr/bin/env node, 就是解决了不同的用户node路径不同的问题,可以让系统动态的去查找node来执行你的脚本文件。可以通过which node命令来找到你本地的node安装路径,将 /usr/bin/env 改为你查找到的node路径即可。 目录结构如下:

my-cli           
├─ bin                
│  └─ main.js  
├─ package-lock.json
└─ package.json              

1.3 在 package.json 文件中指定入口文件为 bin/main.js

{
  "name""my-cli",
  "version""1.0.0",
  "description""",
  "main""bin/cli.js",
  "bin": {
    "test-cli""bin/cli.js" //手动添加入口文件
  },
  "scripts": {
    "test""echo "Error: no test specified" && exit 1"
  },
  "author""",
  "license""ISC"
}

1.4 npm link 链接到全局

npm install可以把发布在npmjs平台上的模块包下载到本地,但这仅限于已经发布的包,对于未发布的包,或者调试一个线上的包,我们如何测试使用呢?npm官方早已考虑到了这一点,给我们提供了测试本地的包的工具指令npm link。 npm link可以帮助我们模拟包安装后的状态,它会在系统中做一个快捷方式映射,让本地的包就好像install过一样,可以直接使用。在MAC中,我们在终端可以直接敲命令,其实是在执行/usr/local/bin目录下的脚本,这个目录可以认为是我们的全局命令所在的地方。 而我们在npm install -g的时候,其实是将相关文件安装在/usr/local/lib/node_modules目录下,同时,在/usr/local/bin目录下会有一个映射脚本,将其指向/usr/local/lib/node_modules下的真实文件。这么做的好处是,在保证只有一份可执行文件的前提下,给命令取别名。 而npm link做的事也差不多,只不过它在/usr/local/lib/node_modules里存的不是真实的文件,而是存了一个快捷方式,指向你当前执行npm link的目录。如果开发的是node包,则执行的命令名和真实执行的文件入口,会通过项目的package.json里bin的配置来获取。

npm link

执行完成:脚手架开发流程

这个时候,在终端执行一下 my-cli, 就会打印出我们的 “my-cli start”脚手架开发流程

2. 工具

手脚架开发过程中使用了一些工具,比如交互提示,获取用户输入,高亮,生成模板等等。这里对他们进行简单的介绍,方便后续的开发。

2.1 commander 自定义命令行指令

commander 是一个命令行解决方案。通过它可以告诉用户脚手架的命令与功能,以及处理用户输入。 安装:npm install commander 使用:

#!/usr/bin/env node
const program = require('commander');
const pkg = require('../package.json');

// 名称,描述,版本号,用法提示。
program
 .name('my-cli')
  .description('这是一个脚手架,用来生成vue/react框架')
  .version(`my-cli ${pkg.version}`)
  .usage('<command> [options]')

program
  .command('create <app-name>')
  .description('创建项目'// 命令描述
  .option('-f,--force''是否强制覆盖已有项目'// 传入action的第二个参数
  .action((name, options) => { // 输入该命令的动作,逻辑实现。
   // name 为用户输入在create命令后面输入的名称
    // options 为 上一步的f参数
    console.log('创建项目name:', name);
    console.log('选项options:', options)
    // create(name, options)
  })

program.parse(process.argv)

执行命令: my-cli create test -f, 会出现如下:脚手架开发流程

2.2 chalk

chalk 是一个终端字符串美化工具。 安装:npm install chalk 使用:chalk.blue 表字体蓝色,chalk.red 表字体红色,chalk.underline 表下划线,chalk.bgRed 表背景红色

const chalk = require('chalk');

console.log(`
  ${chalk.blue('hello')},
  ${chalk.red('this')} 
  ${chalk.underline('is')} 
  ${chalk.bgRed('chalk')}!
`);

美化效果:脚手架开发流程

2.3 inquirer

交互式命令行界面。提供了询问操作者问题,获取并解析用户输入,多层级的提示,提供错误回调,检测用户回答是否合法等能力。 安装:npm install inquirer

inquirer.prompt(arr)方法接受一个数组参数,数组的每一项都有一个type值,用来表示交互命令的类型:

  • **input: **输入类型的交互
  • **number: **输入数字的交互
  • **confirm: **确认类型的交互
  • **list: **单选列表交互
  • **rawlist: **带序号的单选列表交互
  • **expand: **扩展显示的交互
  • **checkbox: **多选列表交互
  • password:  输入类型,但是输入值不可见的交互
  • editor:  编辑器交互

使用:

const inquirer = require('inquirer')

const arr = [
  {
    type'input',
    name: 'projectName',
    message: '项目名称',
    default: 'vue-demo',
  },
  {
    type'list',
    name: 'projectType',
    message: '项目类型',
    default: 'vue2',
    choices: [
      { name: 'vue2', value: 'vue2' },
      { name: 'vue3', value: 'vue3' },
      { name: 'react', value: 'react' }
    ]        
  },
  {
    type'checkbox',
    name: 'plugins',
    message: '插件选择',
    choices: [
      { name: 'babel', value: 'babel' },
      { name: 'eslint', value: 'eslint' },
      { name: 'vue-router', value: 'vue-router' }
    ]
  },
  {
    type'confirm',
    name: 'confirm',
    message: 'confirm',
  }
];

inquirer.prompt(arr).then(answers => {
  console.log('==============');
  console.log(answers);
}).catch(error => {
  console.log('--------------')
  console.log(error)
})

脚手架开发流程

image.png

选择分支,可通过when实现

{
  type: "checkbox",
  name: "preferredJsSkills",
  choices: [
    { name: "Express" },
    { name: "Sequelize" },
    { name: "Graphql" }
  ],
  when: function (answers) {
    return answers.computerLanguage == "JavaScript'
  }
}

校验输入,比如校验邮箱,输入格式错误不允许继续往下走

{
  type"input",
  name"email",
  message"What's your email address?",
  validatefunction (value) {
    let pass = value.match(
      /^[a-zA-Z0-9.!#$%&'*+/=?^_`{l}~-]+@[a-zA-Z0-9-]+(?:.[a-zA-Z0-9-]+)*$/); 
    if (pass) {
        return true;
      }
    return "Please enter a valid email address.";

  },
}

现在来实现简化版vue-cli 选择配置部分

 const arr = [
      {
        name'template'// preset 记录用户选择的选项值。
        type'list'// list 表单选
        message`选择创建的模版:`,
        choices: [
          {
            name'react'// 手动选择配置,自定义特性配置
            value'react'
          },
          {
            name'vue'// 手动选择配置,自定义特性配置
            value'vue'
          }
        ]
      }
    ]

inquirer.prompt(arr).then(answers => {
  console.log('==============');
  console.log(answers);
}).catch(error => {
  console.log('--------------')
  console.log(error)
})

执行 my-cli create test -f 后,会出现以下选项:脚手架开发流程

2.4 ejs

高效的嵌入式 JavaScript 模板引擎。模板可以通过数据进行动态渲染。 安装:npm install ejs 使用: 可以根据用户命令行输入的值,渲染模版。

#! /usr/bin/env node

const inquirer = require('inquirer')
const path = require('path')
const fs = require('fs')
const ejs = require('ejs')

inquirer.prompt([
  {
    type'input',
    name'name'
  }
]).then(answers => {
  // 模版文件目录
  const destUrl = path.join(__dirname, 'templates'); 
  // 生成文件目录
  // process.cwd() 对应控制台所在目录
  const cwdUrl = process.cwd();
  // 从模版目录中读取文件
  fs.readdir(destUrl, (err, files) => {
    if (err) throw err;
    files.forEach((file) => {
      // 使用 ejs 渲染对应的模版文件
      // renderFile(模版文件地址,传入渲染数据)
      ejs.renderFile(path.join(destUrl, file), answers).then(data => {
        // 生成 ejs 处理后的模版文件
        fs.writeFileSync(path.join(cwdUrl, file) , data)
      })
    })
  })
})

2.5 ora 命令行 loading 动效

安装: npm install ora 用法:

const spinner = ora('Loading unicorns').start();

setTimeout(() => {
 spinner.color = 'yellow';
 spinner.text = 'Loading rainbows';
}, 1000);

2.6 download-git-repo 下载模版

安装: npm install download-git-repo 使用: download(repository, destination, options, callback) www.npmjs.com/package/dow…