Reprinted from this blog: Teach you to build a front-end scaffolding tool from scratch - SegmentFault 思否
If you need to know more, you can see the original document. Here I just make a record, so that I can find the document in the future.
1. First create a new project and initialize it
npm init -y
2. Write dependencies in the generated package.json file and execute npm install
"dependencies": {
"chalk": "^1.1.3",
"co": "^4.6.0",
"co-prompt": "^1.0.0",
"commander": "^2.9.0"
}
npm install
3. Then create a bin folder in the root directory, and create a scion file without a suffix in it. This file is the entry file of the entire scaffold, and write code in it. There are four methods as follows, namely adding and deleting , initialize items and view items, add, del, list, init
#!/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('<command>')
program
.command('add')
.description('Add a new template')
.alias('a')
.action(() => {
require('../command/add')()
})
program
.command('list')
.description('List all the templates')
.alias('l')
.action(() => {
require('../command/list')()
})
program
.command('init')
.description('Generate a new project')
.alias('i')
.action(() => {
require('../command/init')()
})
program
.command('delete')
.description('Delete a template')
.alias('d')
.action(() => {
require('../command/delete')()
})
program.parse(process.argv)
if(!program.args.length){
program.help()
}
commander
The specific usage method will not be expanded here, you can go directly to the official website to see the detailed documents.
Then in the terminal node scion, if you see the following information, it means that the entry file has been written.
Usage: scion <command>
Commands:add|a Add a new template
list|l List all the templates
init|i Generate a new project
delete|d Delete a templateOptions:
-h, --help output usage information
-V, --version output the version number
\command
4. Create a folder under the project root directory , which is specially used to store command processing files.
Create a file in the root directory templates.json
and write the following content to store template information:
{"tpl":{}}
Entercommand并新建add.js
"use strict";
const co = require("co");
const prompt = require("co-prompt");
const config = require("./templates");
const chalk = require("chalk");
const fs = require("fs");
module.exports = () => {
co(function* () {
// 分步接收用户输入的参数
let tplName = yield prompt("Template name: ");
let gitUrl = yield prompt("Git https link: ");
let branch = yield prompt("Branch: ");
// 避免重复添加
if (!config.tpl[tplName]) {
config.tpl[tplName] = {};
config.tpl[tplName]["url"] = gitUrl.replace(/[\u0000-\u0019]/g, ""); // 过滤unicode字符
config.tpl[tplName]["branch"] = branch;
} else {
console.log(chalk.red("Template has already existed!"));
process.exit();
}
// 把模板信息写入templates.json
fs.writeFile(
__dirname + "/./templates.json",
JSON.stringify(config),
"utf-8",
(err) => {
if (err) console.log(err);
console.log(chalk.green("New template added!\n"));
console.log(chalk.grey("The last template list is: \n"));
console.log(config);
console.log("\n");
process.exit();
}
);
});
};
Create a new delete.js under command
"use strict";
const co = require("co");
const prompt = require("co-prompt");
const config = require("./templates");
const chalk = require("chalk");
const fs = require("fs");
module.exports = () => {
co(function* () {
// 接收用户输入的参数
let tplName = yield prompt("Template name: ");
// 删除对应的模板
if (config.tpl[tplName]) {
config.tpl[tplName] = undefined;
} else {
console.log(chalk.red("Template does not exist!"));
process.exit();
}
// 写入template.json
fs.writeFile(
__dirname + "/./templates.json",
JSON.stringify(config),
"utf-8",
(err) => {
if (err) console.log(err);
console.log(chalk.green("Template deleted!"));
console.log(chalk.grey("The last template list is: \n"));
console.log(config);
console.log("\n");
process.exit();
}
);
});
};
Create a new init.js under command
"use strict";
const exec = require("child_process").exec;
const co = require("co");
const prompt = require("co-prompt");
const config = require("./templates");
const chalk = require("chalk");
module.exports = () => {
co(function* () {
// 处理用户输入
let tplName = yield prompt("Template name: ");
let projectName = yield prompt("Project name: ");
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 generating..."));
exec(cmdStr, (error, stdout, stderr) => {
if (error) {
console.log(error);
process.exit();
}
console.log(chalk.green("\n √ Generation completed!"));
console.log(`\n cd ${projectName} && npm install \n`);
process.exit();
});
});
};
Create a new list.js under command
"use strict";
const config = require("./templates");
module.exports = () => {
console.log(config.tpl);
process.exit();
};
5. In order to be used globally, we need to package.json
set it inside:
"bin": {
"scion": "bin/scion"
},
6. When debugging locally, execute it in the root directory
npm link
You can scion
bind the command to the global, and you can start it directly scion
as a command in the future without typing in a long node scion
command.
For details, please refer to the original document. This blog is only to record the implementation process.