本文由 简悦 SimpRead 转码, 原文地址 mp.weixin.qq.com
目前日常工作中常用的脚手架有 vue-cli、create-react-app、angular-cli 等等,都是通过简单的初始化命令,完成内容的快速构建。脚手架是我们经常用到的可以提效的工具,经常用在一些代码重复性高的项目中,开发者通过输入命令行、回答问题,就能快速生成一套代码,来避免手动编写。下面我们就来了解脚手架的构建流程和必备工具。
- 搭建框架
1.1 新建 cli 目录
mkdir my-cli && cd my-cli // 创建仓库目录npm init // 初始化 package.json1.2 新建 bin 文件夹,添加 main.js
mkdir bin && cd bin && touch main.js<br style="visibility: visible;">编辑 main.js 文件:
#! /usr/bin/env nodeconsole.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.json1.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.1 commander 自定义命令行指令
commander 是一个命令行解决方案。通过它可以告诉用户脚手架的命令与功能,以及处理用户输入。安装:npm install commander 使用:
#!/usr/bin/env nodeconst 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?", validate: function (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 nodeconst 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) https://www.npmjs.com/package/download-git-repo
- END -
关于奇舞团
奇舞团是 360 集团最大的大前端团队,代表集团参与 W3C 和 ECMA 会员(TC39)工作。奇舞团非常重视人才培养,有工程师、讲师、翻译官、业务接口人、团队 Leader 等多种发展方向供员工选择,并辅以提供相应的技术力、专业力、通用力、领导力等培训课程。奇舞团以开放和求贤的心态欢迎各种优秀人才关注和加入奇舞团。