zoukankan      html  css  js  c++  java
  • 参考vue-cli实现自己的命令行工具(demo)

    准备工作

    1. 包可以使用命令行,是在bin目录下定义自己的脚本文件, 类型这样
    2. 在package.json中注册bin脚本
    {
     "bin": {
        "demo": "bin/demo",
        "demo-init": "bin/demo-init"
      }
    }
    
    1. 安装依赖
    {
       "dependencies": {
        "async": "^3.2.0",
        "chalk": "^4.0.0",  // logger用
        "commander": "^5.0.0", // 开发命令行的主要包
        "consolidate": "^0.15.1",
        "handlebars": "^4.7.6", // 模板
        "inquirer": "^7.1.0",
        "metalsmith": "^2.3.0",
        "read-metadata": "^1.0.0", // 读取meta 文件
      }
    }
    

    开始开发

    1. 定义主入口文件
        const program = require('commander')
        
        program
            .version('1.0.0')
            .usage('<command> [options]')
            .command('init', '主命令的的-h展示内容') // 使用这种方式, 在使用init命令时,会调用同级目录的demo-init 文件夹
    
    1. init命令的实现, init命令要实现的是根据用户输入,拼装参数,copy模板操作
      首先定义meta文件,这里以vue-cli的文件为例子
    const path = require('path')
    const fs = require('fs')
    
    const {
      sortDependencies,
      installDependencies,
      runLintFix,
      printMessage,
    } = require('./utils')
    const pkg = require('./package.json')
    
    const templateVersion = pkg.version
    
    const { addTestAnswers } = require('./scenarios')
    
    module.exports = {
      metalsmith: {
        // When running tests for the template, this adds answers for the selected scenario
        before: addTestAnswers
      },
      helpers: {
        if_or(v1, v2, options) {
    
          if (v1 || v2) {
            return options.fn(this)
          }
    
          return options.inverse(this)
        },
        template_version() {
          return templateVersion
        },
      },
    
      prompts: { // 定义问题,根据问题保存用户选择
        name: {
          when: 'isNotTest',
          type: 'string',
          required: true,
          message: 'Project name',
        },
        description: {
          when: 'isNotTest',
          type: 'string',
          required: false,
          message: 'Project description',
          default: 'A Vue.js project',
        },
        author: {
          when: 'isNotTest',
          type: 'string',
          message: 'Author',
        },
        build: {
          when: 'isNotTest',
          type: 'list',
          message: 'Vue build',
          choices: [
            {
              name: 'Runtime + Compiler: recommended for most users',
              value: 'standalone',
              short: 'standalone',
            },
            {
              name:
                'Runtime-only: about 6KB lighter min+gzip, but templates (or any Vue-specific HTML) are ONLY allowed in .vue files - render functions are required elsewhere',
              value: 'runtime',
              short: 'runtime',
            },
          ],
        },
        router: {
          when: 'isNotTest',
          type: 'confirm',
          message: 'Install vue-router?',
        },
        lint: {
          when: 'isNotTest',
          type: 'confirm',
          message: 'Use ESLint to lint your code?',
        },
        lintConfig: {
          when: 'isNotTest && lint',
          type: 'list',
          message: 'Pick an ESLint preset',
          choices: [
            {
              name: 'Standard (https://github.com/standard/standard)',
              value: 'standard',
              short: 'Standard',
            },
            {
              name: 'Airbnb (https://github.com/airbnb/javascript)',
              value: 'airbnb',
              short: 'Airbnb',
            },
            {
              name: 'none (configure it yourself)',
              value: 'none',
              short: 'none',
            },
          ],
        },
        unit: {
          when: 'isNotTest',
          type: 'confirm',
          message: 'Set up unit tests',
        },
        runner: {
          when: 'isNotTest && unit',
          type: 'list',
          message: 'Pick a test runner',
          choices: [
            {
              name: 'Jest',
              value: 'jest',
              short: 'jest',
            },
            {
              name: 'Karma and Mocha',
              value: 'karma',
              short: 'karma',
            },
            {
              name: 'none (configure it yourself)',
              value: 'noTest',
              short: 'noTest',
            },
          ],
        },
        e2e: {
          when: 'isNotTest',
          type: 'confirm',
          message: 'Setup e2e tests with Nightwatch?',
        },
        autoInstall: {
          when: 'isNotTest',
          type: 'list',
          message:
            'Should we run `npm install` for you after the project has been created? (recommended)',
          choices: [
            {
              name: 'Yes, use NPM',
              value: 'npm',
              short: 'npm',
            },
            {
              name: 'Yes, use Yarn',
              value: 'yarn',
              short: 'yarn',
            },
            {
              name: 'No, I will handle that myself',
              value: false,
              short: 'no',
            },
          ],
        },
      },
      filters: { // 定义filter,根据用户输入来判断是否要copy文件
        '.eslintrc.js': 'lint',
        '.eslintignore': 'lint',
        'config/test.env.js': 'unit || e2e',
        'build/webpack.test.conf.js': "unit && runner === 'karma'",
        'test/unit/**/*': 'unit',
        'test/unit/index.js': "unit && runner === 'karma'",
        'test/unit/jest.conf.js': "unit && runner === 'jest'",
        'test/unit/karma.conf.js': "unit && runner === 'karma'",
        'test/unit/specs/index.js': "unit && runner === 'karma'",
        'test/unit/setup.js': "unit && runner === 'jest'",
        'test/e2e/**/*': 'e2e',
        'src/router/**/*': 'router',
      },
      complete: function(data, { chalk }) { // 构建完成后,用户选择了install,则自动install项目所需依赖
        const green = chalk.green
    
        sortDependencies(data, green)
    
        const cwd = path.join(process.cwd(), data.inPlace ? '' : data.destDirName)
    
        if (data.autoInstall) {
          installDependencies(cwd, data.autoInstall, green)
            .then(() => {
              return runLintFix(cwd, data, green)
            })
            .then(() => {
              printMessage(data, green)
            })
            .catch(e => {
              console.log(chalk.red('Error:'), e)
            })
        } else {
          printMessage(data, chalk)
        }
      },
    }
    
    module.exports = function generate(name, src, dest, done) {
        const opts = getOptions(name, src);
        const metalsmith = Metalsmith(src); // 定义工作目录
        const data = Object.assign(metalsmith.metadata(), {
            destDirName: name,
            inPlace: dest === process.cwd(),
            noEscape: true
        });
    
        metalsmith.use(askQuestions(opts.prompts)) // 设置询问问题
            .use(filterFiles(opts.filters)) // 根据问题答案,来操作filters
            .use(renderTemplateFiles(opts.skipInterpolation)) // cp模板
    
        metalsmith
            .clean(false)
            .source('.')
            .destination(dest)
            .build((err, files) => {
                done(err);
                if (typeof opts.complete === 'function') {
                    const helpers = { chalk, logger, files }
                    opts.complete(data, helpers)
                }
            })
    }
    
  • 相关阅读:
    NCD 2019 M. NCD Salary
    NCD 2019 H. Mr. Hamra and his quantum particles
    Codeforces Testing Round #16 C.Skier
    序列自动机(数组)
    Codeforces #640 div4 F~G (构造二连弹)
    NCD 2019 C. Hasan and his lazy students
    欧拉定理,费马小定理
    微信开发
    异常后显示错误页面
    js窗体间传值
  • 原文地址:https://www.cnblogs.com/clearfix/p/12784885.html
Copyright © 2011-2022 走看看