likes
comments
collection
share

前端cli脚手架的开发之路

作者站长头像
站长
· 阅读数 54

脚手架

什么是脚手架?日常能帮助到我们快速的开发或者提效的都可以称为脚手架,比如: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
评论
请登录