前端工程化-自定义脚手架

1,241 阅读3分钟

效果展示

  • 使用commander命令式效果
  • 使用inquirer交互式效果

初始化操作

  • 使用npm init -y 命令快速生成 package.json 文件
  • 设置 namemain
    {
        "name": "mycli",
        "version": "1.0.0",
        "description": "",
        "main": "index.js",
        "scripts": {
            "test": "echo \"Error: no test specified\" && exit 1"
        },
        "keywords": [],
        "author": "",
        "license": "ISC"
    }
  • 创建index.js文件,输入内容 #!/usr/bin/env node 指定以node环境运行
    #!/usr/bin/env node
    console.log('hello mycli!')v
  • 使用 npm link 命令创建全局module,会在全局node变量下自动生成文件 /node_modules/mycli/index.js
  • 安装依赖 npm install chalk shelljs inquirer --save
    • chalk -- 是一个node输出log的样式库
    • shelljs -- 见名知义是执行shell命令的库
    • inquirer -- 交互式命令库,

目录结构

    - mycli
        - node_modules
        - template
            - vue 
                - vue.html
            - h5
                - h5.html
            ...
        - createProject.js
        - index.js
        - package.json
  • node_modules 脚手架所需要依赖
  • template 该目录下存放的是cli需要的模板, 用户使用脚手架生成的最终项目就是从这里copy出去的
  • createProject.js 拉去项目的代码都在这里
  • index.js 脚手架入口文件
  • package.json 这个就不介绍了

具体代码

  • index.js
    #!/usr/bin/env node
    let program = require('commander')
    let createProject = require('./createProject')

    // 设置版本号和参数,通过 mycli --help 查看
    program.version('1.0.0')
        .option('-t, --type <name>', 'project type')
        .option('-n, --type <name>', 'project type')

    // 捕获命令和参数 eg: mycli create test -t vue
    program
        .command('create <name>')
        .action(function(name) {
            createProject(name, program.type)
        })

    program.parse(process.argv)
  • createProject.js
    let chalk = require('chalk'); // node终端样式库
    let fs = require('fs');
    let path = require('path');
    let inquirer = require('inquirer');

    require('shelljs/global'); // 执行shell脚本

    let log = function(txt) {
        console.log(chalk.green.bold(txt))
    }

    async function createProject(name, type) {
        let p = process.cwd() // 获取当前路径
        cd(p) // shell cd

        // 检测是否存在文件夹, 如果存在,是否需要删除后安装
        if(fs.existsSync(name)) {
            log('project exists, please rename it');
            var questions = [
                {
                type: 'confirm',
                name: 'isRemoveDir',
                message: `delete ${name} ?`,
                default: false,
                }
            ]

            const answer = await inquirer.prompt(questions).then((answers) => {
                return answers
            });

            if(!answer.isRemoveDir) {
                process.exit();
            }
            rm('-rf', name); // shell rm 
            log(`delete ${name} success`)
        }

        let np = path.join(__dirname, 'template', type);
        cp('-R', np+'/', name) // shell cp
        log(`拉取 '${type}' 项目成功!`)
        
        cd(name) // shell cd
        log('设置淘宝镜像源 --- npm config set registry http://registry.npm.taobao.org')
        exec('npm config set registry http://registry.npm.taobao.org') // 执行自定义的shell命令 npm config set registry http://registry.npm.taobao.org
        log('安装模块 --- npm install')
        log('安装模块中...')
        log('安装耗时可能会很长,请耐心等待,您也可以通过 ctrl+c停止安装, 手动 npm install')
        exec('npm install') // 执行自定义的shell命令 npm install

        // 这里的逻辑是自定义的,根据需求自己完成
        if(type != 'jquery') {
            log('正在启动项目')
            exec('npm start') // 执行自定义的shell命令 npm start
        }

        log('脚手架初始化完成')
        process.exit() 

    }

    module.exports = createProject

使用方式

  • mycli --help --help是commander自带的命令, 可以输出脚手架的命令
  • mycli create demo -t vue 这是我们自定义的命令, 创建一个demo文件夹,以vue作为模板

项目改造

使用commander命令操作太过繁琐,并且记不住参数,我们使用inquirer改造成彻底的交互式脚手架

  • 修改 index.js
    #!/usr/bin/env node
    const createProject = require('./createProject')
    const inquirer = require('inquirer');
    const fs = require('fs');
    const path = require('path');

    const promptList = [
        {
            type: 'input',
            message: '请输入项目名',
            name: 'name',
            default: 'my-project',
        },
        {
            type: 'list',
            message: '请选择项目类型',
            name: 'type',
            choices: fs.readdirSync(path.join(__dirname,'template')) // 通过fs模块读取tempate目录下的目录列表
        }
    ]

    inquirer.prompt(promptList).then((answers) => {
        createProject(answers.name, answers.type)
    });
  • 启动命令 mycli, 不用记住繁琐的参数选项,直接通过提示进行操作

总结

自定义脚手架依靠node环境,通过node提供的fs模块,进行文件操作。npm上也提供了各类的命令库(commander , shelljs )和交互式的库(inquirer), 为我们提供了便利,我们主要进行操作就是提供我们自己的脚手架模板