下面是对于 Node.js 实现简单脚手架的详细讲解。
什么是脚手架?
脚手架(Scaffold)是一个前端项目的空架子,提供了一套目录结构、规范、约定以及代码片段等,让我们快速搭建项目并把精力集中在具体的业务上。
Node.js 实现脚手架
Node.js 可以使用许多现有的工具来实现脚手架,例如 Yeoman、create-react-app 等,但在这里我们将使用 commander.js、download-git-repo 和 fs-extra 进行简单的实现。
实现步骤
- 初始化项目
首先,需要使用 npm init
初始化一个 Node.js 项目,并安装 commander
、download-git-repo
和 fs-extra
。
npm init -y
npm install commander download-git-repo fs-extra
- 建立命令行交互
使用 commander
建立命令行交互。我们需要定义一个命令 mycli
,并为其添加一个子命令 init
,以便运行像这样的命令:mycli init myproject
。
#!/usr/bin/env node
const program = require('commander');
const {prompt} = require('enquirer');
program
.command('init <name>')
.description('Initialize an empty project')
.action(async function(name) {
// 等待用户输入和其它操作
});
program.parse(process.argv);
- 构建交互式命令行
使用 enquirer
构建交互式命令行,并询问用户一些问题,例如选择项目模板、项目描述、项目作者等。
program
.command('init <name>')
.description('Initialize an empty project')
.action(async function(name) {
const questions = [
{
type: 'select',
name: 'template',
message: 'Select a Project Template',
choices: [
{name: 'Vue.js', value: 'vue-template'},
{name: 'React', value: 'react-template'}
]
},
{
type: 'input',
name: 'description',
message: 'Enter Project Description'
},
{
type: 'input',
name: 'author',
message: 'Enter Author Name'
}
];
const answers = await prompt(questions);
console.log(answers);
});
- 下载模板
根据用户的选择,使用 download-git-repo
下载相应的项目模板。
const download = require('download-git-repo');
program
.command('init <name>')
.description('Initialize an empty project')
.action(async function(name) {
const questions = [
// ...
];
const answers = await prompt(questions);
console.log('Downloading Template...');
download(`github:myuser/${answers.template}`, name, async function(err) {
if (err) {
console.log(err);
return;
}
console.log('Downloaded Successfully');
// 等待其它操作,例如修改 package.json、安装依赖等
});
});
- 移动文件
将下载下来的项目模板移动到当前工作目录中。
const download = require('download-git-repo');
const path = require('path');
const fse = require('fs-extra');
program
.command('init <name>')
.description('Initialize an empty project')
.action(async function(name) {
const questions = [
// ...
];
const answers = await prompt(questions);
console.log('Downloading Template...');
download(`github:myuser/${answers.template}`, name, async function(err) {
if (err) {
console.log(err);
return;
}
console.log('Downloaded Successfully');
// 移动文件
const root = path.join(process.cwd(), name);
fse.moveSync(`${root}/${answers.template}`, root);
// 等待其它操作,例如修改 package.json、安装依赖等
});
});
- 修改 package.json
从下载下来的项目模板中获取到 package.json
文件,读取其中的信息,并将用户输入的信息和一些默认信息填充进去。最后将修改后的 package.json
写入到当前的工作目录中。
const download = require('download-git-repo');
const path = require('path');
const fse = require('fs-extra');
const {readJSON, writeJSON} = require('fs-extra');
program
.command('init <name>')
.description('Initialize an empty project')
.action(async function(name) {
const questions = [
// ...
];
const answers = await prompt(questions);
console.log('Downloading Template...');
download(`github:myuser/${answers.template}`, name, async function(err) {
if (err) {
console.log(err);
return;
}
console.log('Downloaded Successfully');
// 移动文件
const root = path.join(process.cwd(), name);
fse.moveSync(`${root}/${answers.template}`, root);
// 修改 package.json
const pkg = await readJSON(`${root}/package.json`);
pkg.name = name;
pkg.description = answers.description;
pkg.author = answers.author;
await writeJSON(`${root}/package.json`, pkg, {spaces: 2});
// 等待其它操作,例如安装依赖等
});
});
- 安装依赖
使用 Node.js 的 child_process
模块执行 npm install
命令,安装项目的依赖。
const download = require('download-git-repo');
const path = require('path');
const fse = require('fs-extra');
const {readJSON, writeJSON} = require('fs-extra');
const {execSync} = require('child_process');
program
.command('init <name>')
.description('Initialize an empty project')
.action(async function(name) {
const questions = [
// ...
];
const answers = await prompt(questions);
console.log('Downloading Template...');
download(`github:myuser/${answers.template}`, name, async function(err) {
if (err) {
console.log(err);
return;
}
console.log('Downloaded Successfully');
// 移动文件
const root = path.join(process.cwd(), name);
fse.moveSync(`${root}/${answers.template}`, root);
// 修改 package.json
const pkg = await readJSON(`${root}/package.json`);
pkg.name = name;
pkg.description = answers.description;
pkg.author = answers.author;
await writeJSON(`${root}/package.json`, pkg, {spaces: 2});
// 安装依赖
console.log(`Installing dependencies...`);
execSync(`cd ${root} && npm install`, {stdio: 'inherit'});
console.log('Project initialized');
});
});
现在可以运行 mycli init myproject
来初始化一个新的名为 myproject 的项目了。
示例
以下是使用 mycli init myproject
命令初始化一个 Vue.js 项目的完整示例。
$ mycli init myproject
? Select a Project Template · Vue.js
? Enter Project Description · A new Vue.js project
? Enter Author Name · John
Downloading Template...
Downloaded Successfully
Installing dependencies...
...
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN test@1.0.0 No repository field.
npm WARN test@1.0.0 No license field.
added 220 packages from 289 contributors and audited 221 packages in 10.987s
found 0 vulnerabilities
Project initialized
结论
通过使用 Node.js 的 commander
、download-git-repo
和 fs-extra
,我们可以很容易地实现一个简单的脚手架。当然,这只是一个简单的示例,实际生产环境中需要更多的功能和安全性考虑。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:node如何实现简单的脚手架浅析 - Python技术站