前端cli脚手架的开发之路
脚手架
什么是脚手架?日常能帮助到我们快速的开发或者提效的都可以称为脚手架,比如:vite, vue-cli, nest 这样的都是脚手架。
脚手架相关的包: 作为脚手架是可以直接作为命令使用,所以就必须先认识下 commander, 提供用户命令输入和参数解析的工具; 这里简单的创建一个命令
import { program } from 'commander';
program.command('init').action(() => {
console.log("command init")
})
脚手架在快速开发的过程中会涉及模版的拷贝及处理, 还会用到 fs-extra
import fs from 'fs-extra';
fs.copySync(originalPath, targetPath); //复制文件到目标文件
fs.pathExistsSync(path); //判断当前路径是否存在
fs.emptyDirSync(name); //创建目标文件
还有脚手架也必然涉及交互,所以还需要 inquirer 来作为 prompt 来交互,例如:
import inquirer from 'inquirer';
const selectAnswer = await inquirer.prompt([{
type: 'confirm',
message: '是否重新创建项目',
name: 'reCreate'
}]);
inquirer 还有其他很多种类型,可自行查看手册 当然还有其他的 ora, chalk, figlet 这样的包来帮助美化脚手架,使用体验会更好。
那以上的这些都是脚手架的一个基本要素,下边就实战上一个脚手架吧!
#!/usr/bin/env node
import { program } from 'commander';
import inquirer from 'inquirer';
import path from 'path';
import ora from 'ora';
import { createFolder, isExist, copyTemplate, executeCommand} from './utils';
import { ROOT_PATH } from './constant';
program.version('1.0.1').parse(process.argv);
program.command('new <projectName>').action(async (projectName) => {
const projectPath = ROOT_PATH +'/'+ projectName;
if(isExist(ROOT_PATH +'/'+ projectName)){
const selectAnswer = await inquirer.prompt([{
type: 'confirm',
message: '是否重新创建项目',
name: 'reCreate'
}]);
if(!selectAnswer.reCreate){
return false;
}
const spanner = ora('creating project').start();
createFolder(projectPath);
copyTemplate(path.resolve(__dirname, 'template'), projectName);
executeCommand(projectPath, projectName, spanner)
}else{
const spanner = ora('creating project').start();
createFolder(projectPath);
copyTemplate(path.resolve(__dirname, 'template'), projectName);
executeCommand(projectPath, projectName, spanner)
}
})
import fs from 'fs-extra';
import childProcess from 'child_process';
import Chalk from 'chalk';
export const executeCommand = (projectPath, project, spinner) => {
const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm';
const args = ['install'];
var ls = childProcess.spawn(npm, args, {
shell: true,
stdio: ['inherit', 'pipe'],
cwd: projectPath
})
ls.stdout.on('data', function (data) {
console.log('stdout: ' + data)
})
ls.stderr.on('data', function (err) {
console.log('stderr: ' + err)
})
ls.once('close', function () {
console.log('install success...')
spinner.succeed(Chalk.green('create project successful!'));
console.log(Chalk.blue(`Done! you can start by running:`));
console.log(Chalk.blue.bold('cd ') + Chalk.yellow(project));
console.log(Chalk.blue.bold('npm run dev'));
console.log(Chalk.blue.bold('npm run build'));
})
}
export const copyTemplate = (originalPath, targetPath) => {
return fs.copySync(originalPath, targetPath, {overwrite: true});
}
export const createFolder = (name) => {
try{
fs.emptyDirSync(name)
}catch(err){
throw new Error(err);
}
}
export const isExist = (path) => {
return fs.pathExistsSync(path);
}
以上的就是部分内容,具体的可以参考:github
脚手架 rcli
当然这里我们也做个简单的react脚手架并且已经发布打包, 以下是基本的步骤:
npm i -g rcli
创建项目:
rcli new <project> //项目名称
开始模式:
rcli dev
生产打包:
rcli build
转载自:https://juejin.cn/post/7372914724512956443