在实际的开发过程当中,从零开始创建项目的结构是一件让人头疼的事情,因此各类各样的脚手架工具应运而生。它们功能丰富,但最核心的功能都是可以快速搭建一个完整的项目的结构,开发者只须要在生成的项目结构的基础上进行开发便可,很是简单高效。vue
接下来就让咱们一来看看一个脚手架是如何从0开始搭建的吧。node
总体架构以下图: webpack
一个模板就是一个项目的样板,包含项目的完整结构和信息。 咱们把模板信息都存放在一个文件中scaffold-config-dev.json
。 用户经过选择不一样模板,经过 axios 下载远程仓库模板到本地,完成项目的搭建ios
最终整个脚手架的文件结构以下:git
=================
├── bin
│ └── ivue-material-cli.js
├── node_modules
├── package.json
└── packages
└── src
├── commander
│ └── index.js
├── lib
│ └── utils
│ └── log.js
└── locals
├── index.js
└── zh_CN
└── index.js
复制代码
包名称 | 功能 |
---|---|
commander | 可以更好地组织和处理命令行的输入 |
chalk | 输出有颜色的命令行 |
mz | 在node中使用 es6 |
咱们先从最简单的步骤开始,-v 输出版本号。es6
首先咱们须要知道,-v后命令须要输出什么内容,因此咱们在locals
目录对输出的内容进行国际化内容的管理,在这里咱们一切从简,使用中文内容。github
zh_CN->index.jsweb
module.exports = {
LANG: 'zh_CN',
SHOW_VERSION: '查看当前版本',
NO_COMMAND: '命令不存在'
};
复制代码
而后在locals
文件下对内容文件进行管理。vue-cli
locals->index.jsjson
module.exports = function () {
let lang = process.env.LANG || 'zh_CN';
if (/zh/g.test(lang)) {
return require('./zh_CN');
}
};
复制代码
咱们知道一个好看的命令好必需要有颜色,接下来咱们须要使用chalk
来对命令行进行上色。咱们在 lib->utils
文件夹下对其进行管理。
/**
* @file logger
*/
'use strict';
/* eslint-disable */
const chalk = require('chalk');
const util = require('util');
let log = {};
// 管理命令 log 颜色
let logTypes = [
{
name: 'info',
color: chalk.green,
level: 2
},
{
name: 'error',
color: chalk.red,
level: 4
}
];
logTypes.forEach(function (item) {
/**
* 定义打印日志格式
*
* @param {string} format 要输出的内容.
* @param {...*} varArgs 变长参数.
*/
log[item.name] = function (format, varArgs) {
// 格式化输出字符串
let msg = util.format.apply(null, arguments);
if (msg) {
console.log((log.prefix || 'IVUE') + ' ' + item.color(item.name.toUpperCase()) + ' ' + msg);
}
else {
console.log();
}
};
});
module.exports = log;
复制代码
接下来咱们来编写 -v 命令,咱们在 commander
文件夹下对命令行进行管理,咱们使用 ```commander`` 插件输出命令行由于其可以更好地组织和处理命令行的输入
index.js
// 可以更好地组织和处理命令行的输入
const program = require('commander');
// 内容文件
const locals = require('../locals')();
// 命令行颜色
const log = require('../lib/utils/log');
// 版本号
let version = process.env.VERSION || require('../../../package.json').version;
// 获取输入的命令行
let argv = process.argv[2];
if (argv === '-v' || argv === '--version') {
log.info('ivue version: ', version);
}
// 定义命令
program
// 设置/获取命令用法str
.usage('[commands] [options]')
// 定义顶级命令的参数语法。
.arguments('<cmd> [env]')
// 当使用 --help 时,all 将以这种方式输出。
// 查看当前版本
.option('-v, --version', locals.SHOW_VERSION)
// 注册命令的回调
.action((cmd, env) => {
// 输出错误
if (env) {
log.error(`\`ivue ${cmd} ${env}\` ${locals.NO_COMMAND}`);
}
else {
log.error('`ivue ' + cmd + '` ' + locals.NO_COMMAND);
}
});
// 处理参数
program.parse(process.argv);
复制代码
执行 -v 后输出以下:
接下来咱们来继续构建 -h 帮助命令,修改 commander->index.js
文件
····
// 在node 中使用 es6 语法
const exec = require('mz/child_process').exec;
// 若是后序没有输入命令,执行帮助指令
if (!process.argv[2]) {
let output = exec('ivue -h');
console.log(output[0]);
}
// 获取版本号
else {
let argv = process.argv[2];
if (argv === '-v' || argv === '--version') {
log.info('ivue version: ', version);
}
}
····
复制代码
最终输出以下:
以上也正是 ivue-cli
脚手架的一部分的源码。
下一篇咱们将继续讲解最复杂的功能 init 命令
本文章将一直持续更新到脚手架所有源码的讲解~~~~
若有不对欢迎提出您宝贵的意见
欢迎各位提出 issues
或者 star
。
github仓库地址: