前言:
公司前后端分离项目大致有七八个,技术栈包括react、vue。当初搭建项目的时候都是一个一个进行配置、复制、粘贴。
昨天想起来creat-react-app和vue-cli这些官方脚手架用起来很方便,一键生成项目配置,但是和公司项目实际开发还不是很贴切,用官方的生成后还需要进行配置。
如果自己开发一个脚手架工具,模版用公司那一套的话,生成完的项目基本达成90%。
嗯,就这么开始了~
原理
通过用户输入命令来拉取模版项目,生成实际项目
就是把之前配置好的模版项目,通过用户命令拿过来放在本地。
模版可以放在git上通过远程拉去,也可以放在脚手架项目里。
贴一个模版截图
项目结构
按照国际惯例,先贴目录结构图
下载依赖
在package.json中写入依赖,执行npm install
"dependencies": {
"chalk": "^2.4.2",
"co": "^4.6.0",
"co-prompt": "^1.0.0",
"commander": "^3.0.2",
"which": "^2.0.1"
}
- chalk,给终端的字体加颜色
- co,异步流程控制工具
- co-prompt,提供提示信息,分步接收用户的输入
- commander,处理用户输入的命令
- which,查找指定可执行文件的第一个实例
代码部分
- 新建bin文件夹、创建cli文件(无后缀)
#!/usr/bin/env node --harmony
"use strict";
process.env.NODE_PATH = __dirname + "/../node_modules/";
const program = require("commander");
program.version(require("../package").version);
program.usage("");
//用户输入init回车后,执行init.js
program
.command("init")
.description("Generate a new project")
.action(() => {
require("../command/init")();
});
program.parse(process.argv);
if (!program.args.length) {
program.help();
}
进入bin目录 cd bin
,使用node执行cli文件 node cli
,看到以下信息
Usage: cli
Options:
-V, --version output the version number
-h, --help output usage information
Commands:
init Generate a new project
- 新建command文件夹、创建init.js(处理用户输入的init)
"use strict";
const exec = require("child_process").exec;
const co = require("co");
const prompt = require("co-prompt");
const config = require("../template");
const chalk = require("chalk");
const path = require("path");
module.exports = () => {
co(function*() {
//提示用户输入创建的模版类型
let tplName = yield prompt("Project type (react-p | vue-m): ");
//提示用户输入项目名称
let projectName = yield prompt("Project name: ");
let projectPath = path.resolve(projectName);
//提示用户创建完项目是否执行npm install
let yn = yield prompt("Install Package (Y/N)?: ");
let gitUrl;
let branch;
if (!config.tpl[tplName]) {
console.log(chalk.red("\n × Template does not exit!"));
process.exit();
}
gitUrl = config.tpl[tplName].url;
branch = config.tpl[tplName].branch;
//git远程拉取模版并重新命名
let cmdStr = `git clone ${gitUrl} ${projectName} && cd ${projectName} && git checkout ${branch}`;
console.log(chalk.white("\n Start..."));
exec(cmdStr, (error, stdout, stderr) => {
if (error) {
console.log(error);
process.exit();
}
//如果输入 y|Y,执行npm install
if (/^[y|Y]$/.test(yn)) {
process.chdir(projectPath);
require("../lib/install");
} else {
console.log(chalk.green("\n √ successful!"));
process.exit();
}
});
});
};
- 新建template.json(模版信息)
这两个模版是自己创建的,并不完善,只能当测试项目
{
"tpl": {
"vue-m": {
"url": "https://github.com/smilv/vue-template.git",
"branch": "master"
},
"react-p": {
"url": "https://github.com/smilv/react-template.git",
"branch": "master"
}
}
}
- 新建lib文件夹、创建install.js(执行npm install)
const which = require("which");
const chalk = require("chalk");
const childProcess = require("child_process");
function runCmd(cmd, args, fn) {
args = args || [];
let runner = childProcess.spawn(cmd, args, {
stdio: "inherit"
});
runner.on("close", function(code) {
if (fn) {
fn(code);
}
});
}
function findNpm() {
let npms = ["cnpm", "npm"];
for (let i = 0; i < npms.length; i++) {
try {
which.sync(npms[i]);
console.log("\n " + npms[i] + " install...");
return npms[i];
} catch (e) {}
}
throw new Error(chalk.red("please install npm"));
}
let npm = findNpm();
runCmd(which.sync(npm), ["install"], function() {
console.log(" " + npm + " install end");
console.log(chalk.green("\n √ successful!"));
process.exit();
});
运行使用
在package.json中添加
"bin": {
"smilv-cli": "bin/cli"
},
本地测试时把smilv-cli绑定到全局,在根目录下执行
npm link
另找一个空目录进行测试,执行
smilv-cli init
根据提示输入选择的模版、项目名称、是否需要执行npm install,回车
E:\personal-code>smilv-cli init
Project type (react-p | vue-m): vue-m
Project name: my-app
Install Package (Y/N)?: n
Start...
√ successful!
E:\personal-code>
测试完成。
如何发布到npm就不多说啦~
后记
完整代码地址 https://github.com/smilv/smilv-cli
后会有期。