Автоматизация внешнего интерфейса: внешний интерфейс командной строки Node автоматически создает и публикует систему.

Node.js внешний интерфейс GitHub Командная строка

На данный момент, что касается компании, в которой я работаю, то front-end версия компилируется после завершения разработки, а затем черезftpзагрузить на сервер. Ведь количество проектов вкупе с разделением тестовой среды и формальной среды привело к путанице в управлении. И весь процесс тоже очень хлопотный, приходится делать это вручную пошагово.

Поэтому у меня всегда была идея, могу ли я сделатьVue CliТот же инструмент автоматизации, вы можете вводить команды и выбирать параметры с помощью команд для автоматизации компиляции и выпуска. Как только я это сказал, у меня появилось ~~~

Адрес гитхаба: https://github.com/zuley/zuley-cli

1. Стек технологий

  • chalkУкрасить командную строку, раскрасить и т. д.
  • commanderРазобрать пользовательский ввод командной строки
  • inquirerИнтерактивные функции командной строки, такие как вопросы пользователя и т. д.
  • node-sshssh-модуль
  • oraЭффект загрузки среды командной строки
  • shelljsпереупакованныйchild_processМодуль подпроцесса, удобнее вызывать системные команды.

2. Создайте проект

  1. Использовать напрямуюnpm initСоздать пустой проект
  2. Создайте системный файл без суффикса в корневом каталогеapp, как основной входной файл.

3. Простой пример командной строки

Введите следующий код в файл ввода

const program = require('commander')
const inquirer = require('inquirer')
const chalk = require('chalk')
program
  .command('module')
  .alias('m')
  .description('创建新的模块')
  .option('-n, --name [moduleName]', '模块名称')
  .action(option => {
    console.log('Hello World', option.name)
  })
    
program.parse(process.argv)

Выполните, чтобы увидеть эффект

$ node app m -n zuley // 输出:Hello World zuley

4. Работайте глобально

Вышеприведенный пример слишком громоздкий для ввода.Для выполнения файла необходимо ввести каталог, в котором находится проект.Теперь нам нужен простой способzuley m -n zuley

1. Конфигурацияpackage.jsonсерединаbinполе

"bin": {
    "zuley": "app"
}

2. Зарегистрируйте глобальные команды

Затем зарегистрируйте символическую ссылку, она поместитzuleyСкопируйте это поле вnpmГлобальная папка установки модуляnode_modulesвнутри, то естьzuleyдобавить путь к переменной окруженияPATHсередина.

Если это MAC, вам нужно добавитьsudoпрефикс, с правами администратора.

Все использованные в статьеsudoВсе места являются системными ограничениями MAC, пользователям win необходимо удалить это предложение.

Комментарии были обратной связью и сказали нетsudoВы также можете попробовать не добавлять его первым, а добавить в случае ошибки.

$ npm link

# or mac
$ sudo npm link

3. Объявите исполняемое приложение

Добавьте оператор в начало файла записи, чтобы объявить, что это исполняемое приложение.

#! /usr/bin/env node

...code

4. Выполните команду

$ zuley m -n zuley

5. Структура проекта

В реальной разработке мы используемsrcЭто каталог исходного кода, а автоматическая система публикации размещается в каталоге модулей как один из модулей.

|-/src/ // 源码目录
|---/modules/ 模块目录
|-----/Automation/ // 发布模块目录
|-------index.js // 模块入口文件
|-------config.promps.js  // 选项配置文件
|-------config.service.js // 服务器配置文件
|-app  // 入口文件

6. В файле вводаappЗагрузите модуль системы автоматической публикации

#! /usr/bin/env node

// 导入自动化任务模块
require('./src/modules/Automation/index')

Семь, функция ввода модуля записи

Напишите файл входа модуля/src/modules/Automation/index.js

1. Параметры запроса командной строки

После выполнения команды нам необходимо предоставить интерфейс командной строки для пользователя для ввода или выбора параметров для определения следующего действия. используется здесьinquirerМешок.

Для конкретных случаев использования, пожалуйста, перейдите кnpmИли ищите и учитесь сами.

Ниже приведен фрагмент кода

// 导入选项配置
const prompsConfig = require('./config.promps')

// 项目名称
let { name } = await inquirer.prompt(prompsConfig.name)
// 项目渠道
let source = ''
if (prompsConfig.source[name].length > 0) {
  source = await inquirer.prompt(prompsConfig.source[name])
  source = source.source
}
// 项目环境
let { type } = await inquirer.prompt(prompsConfig.type)
    
// 确认选项
log('请确认你选择了以下选项')
log(chalk.green('项目名称:') + chalk.red(TEXTDATA[name]))
log(chalk.green('项目渠道:') + chalk.red(TEXTDATA[source]))
log(chalk.green('项目环境:') + chalk.red(TEXTDATA[type]))

2. Выполните команду оболочки для компиляции проекта.

используется здесьshelljsМешок.shelljsпереупакованныйchild_processМодуль подпроцесса, удобнее вызывать системные команды.

Все использованные в статьеsudoВсе места являются системными ограничениями MAC, пользователям win необходимо удалить это предложение.

Ниже приведен фрагмент кода

async function compile (config, type) {
  // 进入项目本地目录
  shell.cd(config.localPath)
  if (type === 'TEST') {
    log('测试环境编译')
    shell.exec(`sudo npm run test`)
  } else {
    log('正式环境编译')
    shell.exec(`npm run build`)
  }
  log('编译完成')
}

3. Загрузить файлы

загрузить файл с помощьюnode-sshpackage, который включает в себя несколько простых и удобных в использовании методов. Для получения подробной информации вы можете посетить официальный сайт или выполнить поиск учебных пособий.

Ниже приведен фрагмент кода

/**
 * 上传文件
 * @param {Object} config 项目配置
 */
async function updateFile (config) {
  // 存储失败序列
  let failed = []
  // 存储成功序列
  let successful = []
  let spinner = ora('准备上传文件').start()
  // 上传文件夹
  let status = await ssh.putDirectory(config.localPath + '/dist', config.remotePath, {
    // 递归
    recursive: true,
    // 并发数
    concurrency: 10,
    tick (localPath, remotePath, error) {
      if (error) {
        failed.push(localPath)
      } else {
        spinner.text = '正在上传文件:' + localPath
        successful.push(localPath)
      }
    }
  })
  spinner.stop()
  if (status) { 
    log(chalk.green('完成上传'))
  } else {
    log(chalk.red('上传失败'))
  }
  if (failed.length > 0) {
    log(`一共有${chalk.red(failed.length)}个上传失败的文件`)
    log(failed)
  }
}

Этот пример является лишь простой демонстрацией, а фактическое приложение также должно расширить обработку сбоя загрузки. Например, возобновление с точки останова, возобновление сбойного файла и т. д.

И одна загрузка будет очень медленной, вы можете запустить команду для сжатия, а затем загрузить, а затем выполнить команду сервера для распаковки файла.

Если загрузка не удалась, проверьте, есть ли у удаленного каталога разрешения, и используйте команду для изменения разрешений.

$ chmod -R 777 [目录]

4. Исходный код

1. index.js

const program = require('commander')
const inquirer = require('inquirer')
const chalk = require('chalk')
const ora = require('ora')
const shell = require('shelljs')
const node_ssh = require('node-ssh')
const ssh = new node_ssh()

// 导入选项配置
const prompsConfig = require('./config.promps')
// 导入服务器配置
const serviceConfig = require('./config.service')
const log = console.log

// 字段字典
const TEXTDATA = {
  'A': '项目A',
  'B': '项目B',
  'PC': 'PC 网站',
  'WX': '微信公众号',
  'TEST': '测试环境',
  'PROD': '正式环境',
  '': '其他'
}

// 添加一个名字为 a 别名为 automation 的命令模块
program
  .command('a')
  .alias('automation')
  .description('前端自动化发布系统')
  .action(async option => {
    // 项目名称
    let { name } = await inquirer.prompt(prompsConfig.name)
    // 项目渠道
    let source = ''
    if (prompsConfig.source[name].length > 0) {
      source = await inquirer.prompt(prompsConfig.source[name])
      source = source.source
    }
    // 项目环境
    let { type } = await inquirer.prompt(prompsConfig.type)
    
    // 确认选项
    log('请确认你选择了以下选项')
    log(chalk.green('项目名称:') + chalk.red(TEXTDATA[name]))
    log(chalk.green('项目渠道:') + chalk.red(TEXTDATA[source]))
    log(chalk.green('项目环境:') + chalk.red(TEXTDATA[type]))
    
    // 获取配置
    let config = serviceConfig[`${name}-${source}-${type}`]

    log(`使用服务器配置:${name}-${source}-${type}`)

    // 编译项目
    compile(config, type)

    // 连接服务器
    await ConnectService(config)

    // 上传文件
    await updateFile(config)
  })

program.parse(process.argv)

/**
 * 连接服务器
 * @param {Object} config 项目配置
 */
async function ConnectService (config) {
  log('尝试连接服务:' + chalk.red(config.service.host))
  let spinner = ora('正在连接')
  spinner.start()
  await ssh.connect(config.service)
  spinner.stop()
  log(chalk.green('成功连接到服务器'))
}

/**
 * 上传文件
 * @param {Object} config 项目配置
 */
async function updateFile (config) {
  // 存储失败序列
  let failed = []
  // 存储成功序列
  let successful = []
  let spinner = ora('准备上传文件').start()
  // 上传文件夹
  let status = await ssh.putDirectory(config.localPath + '/dist', config.remotePath, {
    // 递归
    recursive: true,
    // 并发数
    concurrency: 10,
    tick (localPath, remotePath, error) {
      if (error) {
        failed.push(localPath)
      } else {
        spinner.text = '正在上传文件:' + localPath
        successful.push(localPath)
      }
    }
  })
  spinner.stop()
  if (status) { 
    log(chalk.green('完成上传'))
  } else {
    log(chalk.red('上传失败'))
  }
  if (failed.length > 0) {
    log(`一共有${chalk.red(failed.length)}个上传失败的文件`)
    log(failed)
  }
}

/**
 * 编译源码
 * @param {Object} config 项目配置
 * @param {String} type 编译类型 TEST or PROD
 */
async function compile (config, type) {
  // 进入项目本地目录
  shell.cd(config.localPath)
  if (type === 'TEST') {
    log('测试环境编译')
    shell.exec(`sudo npm run test`)
  } else {
    log('正式环境编译')
    shell.exec(`sudo npm run build`)
  }
  log('编译完成')
}

2. Исходный код конфигурации опции: config.promps.js

Этот файл конфигурирует данные, введенные или выбранные пользователем в командной строке, для последующей склейки и генерации.A-WX-TESTполе класса.

A-WX-TESTОт имени выбранного пользователя: Project A-WeChat-Test Environment

Программа пройдет через это поле сплайсинга, чтобыconfig.service.jsПолучить конфигурацию проекта в

/**
 * 自动化模块 - 选项配置文件
 */
module.exports = {
  // 项目名字
  name: [
    {
      type: 'list',
      name: 'name',
      message: '请选择要发布的项目',
      choices: [
        {
          name: '项目A',
          value: 'A'
        },
        {
          name: '项目B',
          value: 'B'
        }
      ]
    }
  ],
  // 项目渠道
  source: {
    'A': [
      {
        type: 'list',
        name: 'source',
        message: '请选择要发布的渠道',
        choices: [
          {
            name: 'PC网站',
            value: 'PC'
          },
          {
            name: '微信',
            value: 'WX'
          }
        ]
      }
    ],
    'B': [
      {
        type: 'list',
        name: 'source',
        message: '请选择要发布的渠道',
        choices: [
          {
            name: 'PC网站',
            value: 'PC'
          },
          {
            name: '微信',
            value: 'WX'
          }
        ]
      }
    ]
  },
  // 项目环境
  type: [
    {
      type: 'list',
      name: 'type',
      message: '请选择发布环境',
      choices: [
        {
          name: '测试环境',
          value: 'TEST'
        },
        {
          name: '正式环境',
          value: 'PROD'
        }
      ]
    }
  ]
}

3. Исходный код конфигурации сервера: config.service.js

Конфигурация сервера настроена только с двумя в качестве демонстрации, а реальная ситуация дополнена.

существуетGitHubВытягивая тест проекта, не забудьте изменить вторичный файл.

  1. Измените сервер на свой собственный сервер и пароль учетной записи ssh.
  2. Изменить локальный каталог проекта и удаленный каталог
  3. A-WX-TESTВ этом поле представлены параметры, введенные пользователем, см.config.promps.js
// 服务器 A
const serviceA = {
  // 服务器 IP
  host: 'xxx.xxx.xxx.xxx',
  // ssh 账号
  username: 'xxx',
  // ss 密码
  password: 'xxxxxx'
}

module.exports = {
  // 项目A,微信测试环境
  'A-WX-TEST': {
    service: serviceA,
    // 本地目录
    localPath: '/Users/zuley/ChuDaoNew/minshengjingwu-h5',
    // 远程目录
    remotePath: '/root/html/test'
  },
  // 项目A,微信正式环境
  'A-WX-PROD': {
    service: serviceA,
    // 本地目录
    localPath: '/Users/zuley/ChuDaoNew/minshengjingwu-h5',
    // 远程目录
    remotePath: '/root/html/prod'
  }
}

8. Выполняйте автоматические выпуски

Выполните следующую команду, чтобы запустить автоматизацию

$ zuley a

Если есть ошибка во вводе, можно ввести команду завершения

$ Ctrl+C

9. Справочные статьи

Адрес гитхаба: https://github.com/zuley/zuley-cli

Следуйте старому драйверу, чтобы играть в командную строку Node.

мел: украсить командную строку, раскрасить

командующий: Разобрать пользовательский ввод командной строки

inquirer: интерактивные функции командной строки, такие как вопросы пользователя и т. д.

узел-ssh: модуль ssh

ora: эффект загрузки среды командной строки

shelljs: удобнее вызывать системные команды