本次时《建立Node脚手架》的第二节. 第一节中介绍了建立Node脚手架时经常使用的工具库. 详情请查看(上)。本节将一步一步开发一个Node工具, 实现的功能是: 相似create-react-app, 经过这个工具, 能够建立基本的react编程结构.javascript
clone一份前一节的项目代码cli-demo. 新项目取名为create-react-redux-app-cli. 文件结构以下:java
- bin
- cli
- lib
- package.json
复制代码
在bin节点下, 添加一个crra命令, 引用指向bin/cli. 这样就能够执行crra命令node
"bin": {
"crra": "./bin/cli"
},
复制代码
进入项目的根目录. 执行react
npm link
复制代码
安装完成后, crra命令就能够在任意地方执行了.webpack
到此, 准备工做已经完成了.git
接下来咱们开干吧...github
bin/cli文件web
#!/usr/bin/env node
const path = require('path');
const program = require('commander');
program
.version(require('../package.json').version, '-v, --version');
program
.command('create <ProjectName>')
.description('Create a new Project')
.action(async (projectName) => {
console.log(projectName);
})
program.parse(process.argv);
复制代码
用来下载git上的基础项目做为模板.npm
咱们先安装一个新的工具库.编程
npm i -D download-git-repo
复制代码
lib/download.js文件.
const { promisify } = require('util');
const ora = require('ora');
/** * 从git仓库上下载项目到本地 * @param {String} repo git仓库地址 * @param {String} desc 本地的路径 */
const clone = async function (repo, desc) {
// 包装成一个promise方法.
const download = promisify(require('download-git-repo'));
// 显示下载进度.
const process = ora(`建立中...`);
process.start();
try {
await download(repo, desc);
process.succeed();
} catch (error) {
process.fail(error.message);
}
};
module.exports = {
clone
};
复制代码
封装一个exec方法, 用来执行命令行命令.
const childProcess = require('child_process');
const which = require('which');
const chalk = require('chalk');
/** * 查找系统中用于安装依赖包的命令 */
function findNpm() {
const npms = ['tnpm', 'cnpm', 'npm'];
for (let i = 0; i < npms.length; i++) {
try {
// 查找环境变量下指定的可执行文件的第一个实例
which.sync(npms[i]);
return npms[i]
} catch (e) {
}
}
throw new Error(chalk.red('请安装npm'));
}
/** * 开启子进程来执行命令 * @param {String} cmd 待执行的命令 * @param {Array} args 命令执行时的参数. * @param {Function} fn 执行完成时的回调. */
function exec(cmd, args, fn) {
args = args || [];
const runner = childProcess.spawn(cmd, args, {
stdio: 'inherit'
});
runner.on('close', function (code) {
if (fn) {
fn(code);
}
})
}
module.exports = {
exec,
findNpm
};
复制代码
用来安装新项目的依赖.
const which = require('which');
const { exec, findNpm } = require('./exec');
/** * 执行npm install命令, 安装项目依赖. */
const install = () => {
const npm = findNpm();
exec(which.sync(npm), ['install'], function () {
console.log(npm + '安装完成');
});
};
module.exports = {
install
};
复制代码
用来定义更新package.json的方法.
const chalk = require('chalk');
const fs = require('fs-extra');
/** * 更新文件内容. * @param {String} filePath * @param {Object} contents */
const updateFile = (filePath, contents) => {
if(fs.existsSync(filePath)){
const fileContent = Object.assign({}, require(filePath), contents);
fs.writeJSONSync(filePath, fileContent, { spaces: '\t' });
} else{
throw new Error(chalk.red(`${filePath}不存在`));
}
};
module.exports = {
updateFile
};
复制代码
#!/usr/bin/env node
const path = require('path');
const program = require('commander');
const inquirer = require('inquirer');
const { updateFile } = require('../lib/file');
const { install } = require('../lib/install');
// 定义和用户交互时的questions
const prompt = () => {
return inquirer.prompt([
{
type: 'input',
name: 'author',
message: '请输入做者的名称'
},
{
type: 'input',
name: 'repository',
message: '请输入GitHub的项目地址'
},
{
type: 'confirm',
name: 'isOk',
message: '请确认输入是否ok?'
}
])
};
program
.version(require('../package.json').version, '-v, --version');
program
.command('create <ProjectName>')
.description('建立一个新项目')
.action((projectName) => {
prompt().then(async (results) => {
const { author, repository, isOk } = results;
if (!isOk) {
return;
}
// 1. clone项目
const { clone } = require('../lib/download');
console.log('🚀建立项目: ' + projectName);
await clone('github.com:ichenzhifan/react-redux-base', projectName);
console.log(`项目${projectName}建立成功`);
// 2. 更新package.json的配置.
const packageJson = path.join(path.resolve(projectName), 'package.json');
const repositoryObj = repository ? {
type: "git",
url: repository
} : {};
updateFile(packageJson, {
name: projectName,
author,
repository: repositoryObj
});
// 3. 安装依赖
console.log('安装依赖...')
// 将node工做目录更改为构建的项目根目录下
const projectPath = path.resolve(projectName);
process.chdir(projectPath);
// 执行安装命令
install();
});
})
program.parse(process.argv);
复制代码
到此, 一个功能完整的cli工具就作好了.
请看: 《建立Node脚手架工具(下)》