《前端那些事》从0到1开发简单脚手架

树酱但愿将前端的乐趣带给你们 本文已收录 github.com/littleTreem… 喜欢就star✨前端

上一篇树酱讲《前端工程化那些事》,聊到脚手架,不过期间比较仓促,致使内容较少,而在我实践开发中,随着新项目越来越多,脚手架工具就起到提升效能的做用,借此机会跟小伙伴们分享下我是如何从0到1开发一个简单脚手架vue

1.什么是脚手架

脚手架用于快速生成新项目的目录模板,并集成一系列体系化工具的安装,可以提高前端开发人员的效率,减小copy操做node

目前比较主流的脚手架:react

  • Vue脚手架:Vue-cli
  • React脚手架:create-react-app
  • Yeoman

2.我指望的脚手架

而我所指望的脚手架是怎么样的呢?git

当我要开启一个新项目的开发,能够快速生成新项目的目录模板,而这个目录结构是每一个项目统一个模版规范(目录规范),同时也设定了通用的配置包括以下github

  • 通用的Webpack配置(vue cli 3x 以上是vue.config.js)
  • 统一的Eslint 校验规则:如Airbnb、eslint-plugin-vue等(eslintConfig)
  • 统一的单元测试框架配置:单元测试覆盖率、测试的目录等
  • 统一的Dockerfile和jenkinsfile (用来打包成镜像和部署流水线定义)
  • 统一babel的配置(.babelrc或babel.config.js)
  • 统一的常量配置(缓存字段等等)
  • 不一样环境的配置文件(development、test、production)

没有脚手架,我只能经过copy拷贝代码来完成,这样繁琐又机械化的操做浪费大量时间,并且还可能在拷贝过程当中,由于某个细节出错,致使项目出错,排查问题又耗时。或许你可能会想,咱们不是能够用vue或者react官方的脚手架来生成模版吗?是,可是这种方式建立的模版不必定符合你内部结构化标准web

为了解决上述问题,脚手架就起到一个相当重要的角色,咱们能够经过脚手架来约束好规范,统一的配置,来打通新项目的开发工具链,一方面提高开发效率,一方面则提升项目对接可维护性及新员工熟悉项目简易性。shell

3.开发脚手架

3.1 如何开发

若是是要开发一个高度可定制化的脚手架,须要考虑的因素不少,由于某种限制,选择了一种简易的方式来实现内部的脚手架工具,远离就是经过准备两个模版,一个是pc端的,另外一个是mobile端的模版,而后用git管理起来,我须要以下工具:npm

  • 可用于控制台选择的工具:inquirer
  • 可处理控制台命令的工具:commander
  • 可改变输出log颜色的工具:chalk
  • 可执行shell命令的工具: child_process

入口文件 index.jsjson

#!/usr/bin/env node

const fs = require('fs');
const path = require('path');
const chalk = require('chalk');
const commander = require('commander');
const inquirer = require('inquirer');
const checkDire = require('./utils/checkDire.js');
const { exec } = require('child_process');
const { version } = require('../package.json');
const { promptTypeList } = require('./config');

//version 版本号
commander.version(version, '-v, --version')
  .command('init <projectName>')
  .alias("i")
  .description("输入项目名称,初始化项目模版")
  .action(async (projectName,cmd) => {
    await checkDire(path.join(process.cwd(),projectName),projectName);   // 检测建立项目文件夹是否存在
    inquirer.prompt(promptTypeList).then(result => {
      const {url, gitName, val} = result.type;
      console.log("您选择的模版类型信息以下:" + val);
      console.log('项目初始化拷贝获取中...');
      if(!url){
        console.log(chalk.red(`${val} 该类型暂不支持...`));
        process.exit(1);
      }
      exec('git clone ' + url, function (error, stdout, stderr) {
        if (error !== null) {
          console.log(chalk.red(
            `clone fail,${error}`
          ));
          return;
        }
        fs.rename(gitName, projectName, (err)=>{
          if (err) {
            exec('rm -rf '+gitName, function (err, out) {});
            console.log(chalk.red(`The ${projectName} project template already exist`));
          } else {
            console.log(chalk.green(`The ${projectName} project template successfully create(项目模版建立成功)`));
          }
        });
      });
    })
  });
commander.parse(process.argv);

复制代码

这里定义的是npm包命令bin的入口文件

须要注意在文件前面定义#!/usr/bin/env node

#!/usr/bin/env node设置后,可让系统动态的去查找node,已解决不一样机器不一样用户设置不一致问题

检测目录是否存在

// utils/checkDire.js
const fs = require('fs');
const chalk = require('chalk');
const path = require('path');

module.exports = function (dir,name) {
  let isExists = fs.existsSync(dir);
  if (isExists) {
    console.log(chalk.red(
      `The ${name} project already exists in  directory. Please try to use another projectName`
    ));
    process.exit(1);
  }
复制代码

配置文件

// config/index.js
配置文件
/*
  @dest: 使用配置文件
  @Author: tree
 */
module.exports  = {
  promptTypeList:[{
      type: 'list',
      message: '请选择拉取的模版类型:',
      name: 'type',
      choices: [{
        name: 'mobile',
        value: {
          url: '',
          gitName: 'vue-web-template',
          val:'移动端模版'
        }
      },{
        name: 'pc',
        value: {
          url: 'https://github.com/littleTreeme/vue-web-template.git',
          gitName: 'vue-web-template',
          val:'PC端模版'
        }
      }]
  }],
};
复制代码

源码连接:github.com/littleTreem… 若是你以为实用请给个🌟支持,在此感谢

3.2 工具详解

  • inquirer

一个用户与命令行交互的工具

基本用法 🔗使用文档

const inquirer = require('inquirer');

const promptList = [
     type: 'list',
     message: '请选择拉取的模版类型:',
     name: 'type',
      choices: ['mobile','pc']
];

inquirer.prompt(promptList).then(type => {
    console.log(type); // 返回 mobile 或 pc
})
复制代码

场景以下

  • commander

commander是一个轻巧的nodejs模块,提供了用户命令行输入和参数解析强大功能

使用到的commander API 🔗使用文档

const commander = require('commander');
commander.version(version, '-v, --version')
  .command('init <projectName>') 
  .alias("i") 
  .description("输入项目名称,初始化项目模版") 
  .action(async (projectName,cmd) => {
      console.log(projectName,'你输入的<projectName>')
  })
commander.parse(process.argv);
  
// command – 定义命令行指令,后面可跟上一个name,用空格隔开
// alias – 定义一个更短的命令行指令
// description – 描述,它会在help里面展现
// option – 定义参数
// action – 注册一个callback函数
// parse - 解析命令行
 
复制代码
  • chalk

node终端样式库,让你的日志样式更美观,主要用chalk来区别错误与成功的日志

如何使用 🔗使用文档

const chalk = require('chalk');

// 报错日志用红色来显示
chalk.red(`The project already exists in  directory. Please try to use another projectName`));

// 成功日志用绿色来显示
chalk.green(`The project template successfully create(项目模版建立成功)`);
复制代码

3.3 如何使用

能够先经过试着本地安装尝试流程阅读使用文档

以下所示是本身开发的一个kdv-cli运行时的示意图

那么 kdv-cli 命令是怎样映射进去的?,缘由在于 package.json 里面的 定义了 bin 字段;

// package.json
"bin": {
    "kdv-cli": "./bin/index.js"
 },
复制代码

我选择pc类型,而后建立名为 test的项目(暂还不支持mobile)

重复建立则报错

拉取后的项目目录结构以下所示:

4.注意事项

  • 注意事项

当你完成脚手架开发时,你想本地测试是否成功运做,会出现这种状况

这是由于你本地找不到命令执行的路径,没有映射到bin中去,那么如何在本地测试刚开发玩的脚手架工具命令,那就是用npm link,以下所示便可

5.结尾

经过上文所述,咱们就从0到1完成kdv-cli脚手架开发 ,该工具或许不太适用于每一个场景,但能够梳理一个简单的脚手架的搭建过程,为后期作更全面、功能更强大的脚手架奠基基础,若是你喜欢,请给树酱点个✨ github.com/littleTreem…

往期文章

相关文章
相关标签/搜索