⚠️ Эта статья является первой подписанной статьей сообщества Nuggets, и ее перепечатка без разрешения запрещена.
предисловие
в предыдущем постеДинамический шаблонПосле этого мы выполнили базовую функциональность, необходимую для обычного инструмента CLI, в том числеСборка (веб-пакет, накопительный пакет),Качество (независимая проверка),Шаблоны (динамическое управление шаблонами)И так по модулям, которыми можно управлять унифицированным способом.
Но этого мало, производительности больше не высвобождается, нужна инфраструктурная задачаТимбилдинг,Быть не у дел или просто полагаться на нескольких одноклассников просто недостаточно.
В небольшой команде разработка CLI может учитывать все потребности и регулярно обновлять инструменты или сценарии CLI, но по мере роста команды, особенно с появлением многопрофильных команд, разработка CLI не может реагировать на потребности каждой команды в режиме реального времени, обеспечивая функции устройства не могут в полной мере удовлетворить потребности каждого.
Каждый проект и команда будут иметь разные функциональные настройки в соответствии с их собственным бизнесом и потребностями.Если набор CLI будет переработан, будет повторяться работа, и нет единого входа для управления инструментами.
Следовательно, с теми же требованиями, что и у настраиваемых шаблонов, нам нужно делегировать эти индивидуальные требования каждой бизнес-группе и позволить учащимся, которым они нужны, самостоятельно разрабатывать и поддерживать эти проблемы, в то время как разработчикам необходимо преобразовать интерфейс командной строки, чтобы обеспечить стандартизированную интеграцию вход для удовлетворения требований класса конфигурируемых инструментов.
Перед формальной разработкой функции мы делаем простой дизайн функции, которая будет разрабатываться в обычном режиме, и проводим предварительное техническое предварительное исследование, чтобы увидеть, может ли технология удовлетворить проект функции.Если это не может быть завершено, план дизайна должен быть измененный.
Дизайн и предварительное исследование
Поскольку пользователь не знает, является ли команда встроенной или сторонней, требуется основная запись, подобная маршрутизатору, включая команды для встроенных и сторонних подключаемых модулей, и после того, как пользователь вводит команду, различные плагины называются.
Чтобы добиться этого эффекта, нам нужно изменить предыдущую команду command.
В предыдущей разработке все наши командные команды были напрямую жестко закодированы в коде, как показано ниже:
program
.version('0.1.0')
.description('start eslint and fix code')
.command('eslint')
.action((value) => {
execEslint()
})
Нет возможности подгружать сторонние плагины, можно попробовать выставить все команды в виде элементов конфигурации, а потом сформировать массив команд, а потомПерейдите, чтобы получить соответствующие команды, пакетная загрузка.
internally
В этом каталоге находятся встроенные команды CLI, в том числе команды сценария, которые были написаны ранее, такие какeslint
(Другие команды также записываются таким же образом):
import { execEslint } from '@/index'
export const eslintCommand = {
version: '0.1.0',
description: 'start eslint and fix code',
command: 'eslint',
action: () => execEslint()
}
export default [
eslintCommand
]
Здесь мы видим, что все команды были преобразованы в объект и выставлены в виде объекта, а затем на главном входе вводится пакетная регистрация конфигурации, как показано ниже.встроенныйЗаказ:
import path from "path";
import alias from "module-alias";
alias(path.resolve(__dirname, "../../"));
import { Command } from 'commander';
import internallyCommand from './internally'
const program = new Command(require('../../package').commandName);
interface ICommand {
version: string
description: string
command: string
action: (value?: any) => void
}
const initCommand = (commandConfig: ICommand[]) => {
commandConfig.forEach(config => {
const { version, description, command, action } = config
program
.version(version)
.description(description)
.command(command)
.action((value) => {
action(value)
})
})
}
initCommand(internallyCommand)
program.parse(process.argv);
Наконец, используйте инструмент командной строки, чтобы попытаться получить команду CLI.Из рисунка ниже видно, что команда может быть зарегистрирована нормально.
Разработка пользовательского функционала плагина регистрации
После того, как дизайн функции завершен, также проверяется, что регистрация команд также может быть выполнена путем обхода конфигурации.Далее мы официально введем функцию разработки сторонних плагинов.
процесс регистрации
Схема простой регистрации выглядит следующим образом:
- Введите имя стороннего плагина
- Установить зависимости
- Зарегистрировано и ожидает использования
Для основного CLI нельзя принимать слишком персонализированные и кастомизированные плагины, что повлияет на структуру CLI, поэтому нужно сделать ограничение на шаблон плагина CLI, за исключением того, что выходной формат в соответствии с приведенным выше форматом встроенного плагина.Кроме того, нам также необходимо сделать ограничение на имя плагина, зависимости и т. д., но это можно согласовать, предоставив шаблон плагина CLI.
за наших@boty-design/fe-cli
, мы принимаем только@boty-design/fe-plugin-***
Приходят плагины для именованных форматов. Это правило может быть согласовано в соответствии с соглашением об именах команды, а не единственным.
Таким образом, при добавлении шаблона требуются две проверки.Первый уровень проверки — передача имени проверки, а второй уровень — установка зависимостей.Если установка зависимости не удалась, она не будет успешно добавлена.
Проверка имени плагина, мы можем пройтиinquirer
изvalidate
функция для проверки:
import inquirer from 'inquirer';
const promptList = [
{
type: 'input',
message: '请输入插件名称:',
name: 'pluginName',
default: 'fe-plugin-eslint',
validate(v: string) {
return v.includes('fe-plugin-')
},
transformer(v: string) {
return `@boty-design/${v}`
}
}
];
export const registerPlugin = () => {
inquirer.prompt(promptList).then((answers: any) => {
const { pluginName } = answers
console.log(pluginName)
})
}
После прохождения проверки команды компонента вы можете пройтиlatest-version
Чтобы проверить, существует ли уже опубликованный пакет, чтобы избежать сбоя установки и исключения команды регистрации.
После проверки правильности пакета npm подключаемого модуля продолжайте использовать shelljs для установки зависимостей, соответствующих подключаемому модулю:
export const npmInstall = async (packageName: string) => {
try {
shelljs.exec(`yarn add ${packageName}`, { cwd: process.cwd() });
} catch (error) {
loggerError(error)
process.exit(1)
}
}
Наконец, нам нужно кэшировать зарегистрированные плагины в виде файлов, читать файлы конфигурации при следующем использовании, вводить команды плагинов и предоставлять их пользователям.
export const updatePlugin = async (params: IPlugin) => {
const { name } = params
let isExist = false
try {
const pluginConfig = loadFile<IPlugin[]>(`${cacheTpl}/.plugin.json`)
let file = [{ name }]
if (pluginConfig) {
isExist = pluginConfig.some(tpl => tpl.name === name)
if (!isExist) {
file = [
...pluginConfig,
{ name }
]
}
}
writeFile(cacheTpl, '.plugin.json', file)
loggerSuccess(`${isExist ? 'Update' : 'Add'} Template Successful!`)
} catch (error) {
loggerError(error)
}
}
Код примера аналогичен предыдущему tpl, но сохраненного контента тоже меньше. По сути, его не нужно обновлять. По умолчанию каждый раз может быть установлена последняя версия. Если вы хотите сделать что-то сложное, вы можно кстати версию написать, чтобы можно было следить Предусмотрена функция переключения версий(кажется, не имеет большого смысла).
После завершения всех вышеперечисленных разработок, наконец, давайте выполним команду, чтобы увидеть эффект:
boty tEslint
Мы получили его при регистрации стороннего плагина, как видно из рисунка выше, сторонний был зарегистрирован.@boty-design/fe-plugin-eslint
После плагина пользователи уже могут использоватьtEslint
заказ.
После этого вы можете позволить студентам, изучающим бизнес, разрабатывать свои собственные плагины, чтобы обогатить рынок плагинов CLI, но все равно необходимо иметь определенные спецификации для шаблонов плагинов. далее мы разработаем шаблон подключаемого модуля CLI.
Шаблон плагина CLI
Самым большим ограничением шаблона подключаемого модуля является предоставление той же конфигурации регистрации команд, что и встроенной команды, чтобы учащиеся, разрабатывающие сторонние подключаемые модули, могли в максимальной степени настраивать функции.
import { getEslint } from './eslint'
export const execEslint = async () => {
await getEslint()
}
export const eslintCommand = {
version: '0.1.0',
description: 'start eslint and fix code',
command: 'tEslint',
action: () => execEslint()
}
export default [
eslintCommand
]
module.exports = eslintCommand
Здесь я напрямую перенес команды CLI.Поле bin в package.json — это команда, которая может продолжать использовать eslint после завершения глобальной установки, а «lib/index.js» определен в основном свойстве, чтобы иметь возможность используйте команду CLI, при входе требуйте соответствующую конфигурацию регистрации.
Здесь вы можете обнаружить, что когда CLI был впервые разработан, все команды были помещены в индекс, а затем указаны в корзине, так что наш CLI также может использоваться как обычный пакет npm другими кодами, поэтому эта миграция Для меня , это очень просто.
Управление шаблонами плагинов
Если открытых сторонних плагинов много, поддерживать плагины таким образом будет проблематичнее, в том числе при установке CLI сторонние плагины не устанавливаются по умолчанию, и это невозможно интуитивно увидеть, сколько их будет в будущем Плагины выпускаются и обновляются.
Поэтому, чтобы упростить его использование, мы можем создать поддельный рынок плагинов для управления им.
Потому что репозиторий для этого CLI находится на github.boty organization, то мы также можем поместить в него соответствующие плагины, а затем получить нужную нам информацию через API-интерфейс github.
Как и выше, мы смогли получить необходимую нам информацию через API github.Далее мы можем делать все, что захотим, и выполнять все настраиваемые функции, которые вы хотите, включая обновление плагинов, обновление установленных плагинов, переработку заброшенных плагинов и т.д. Все функции.
Если позволяют условия, вы можете разработать фон управления подключаемыми модулями, который может делать больше вещей.
Рефакторинг проекта
В предыдущей CLI-разработке для ускорения работы многие детали по коду были еще очень грубыми, в процессе непрерывного вывода цикла статей в CLI постоянно добавлялись новые функции, поэтому многие прежние функции не были реализованы ну так пользуйтесь развитием новых функций, а прежние детали улучшите кстати.
fs-extra
использоватьfs-extra
заменятьfs
модуль.
Модуль fs-extra — это расширение системного модуля fs, которое предоставляет более удобные API и наследует API модуля fs.
В предыдущих файловых операциях мы использовалиfs
модуль, какnode
Представленные базовые модули все еще ограничены в развитии бизнеса, например, при чтении файлов необходимо пройтиJSON.parse
Его можно использовать после сериализации.
export const loadFile = <T = {}>(path: string): T | false | undefined => {
try {
if (!fs.existsSync(path)) {
return false
}
const data = fs.readFileSync(path, 'utf8');
const config = JSON.parse(data);
return config
} catch (err) {
loggerError(`Error reading file from disk: ${err}`);
}
}
можно использоватьfs-extra
который предоставилreadJsonSync
Замена APIfs
изreadFileSync
, что сокращает этапы сериализации json и улучшает читаемость кода.
try {
if (!fs.pathExistsSync(rePath)) {
return false
}
const data = fs.readJsonSync(rePath);
loggerSuccess('file existed!')
return data
} catch (err) {
loggerError(`Error reading file from disk: ${rePath}`);
}
С точки зрения хранения файлов это еще более полезно и может уменьшить объем кода.fs-extra
Предоставляет более удобный API для манипулирования файлами, и нуждающиеся друзья могут его прочитатьfs-дополнительная документация, я не буду делать здесь слишком много расширения.
Изменить каталог кеша
Студенты, которые собирались вместе раньше, должны знать, что корневой путь проекта существует в предыдущем каталоге кеша, поэтому в настоящее время существует ситуация, когда каталог кеша теряется после переустановки и обновления, поэтому мы можем использовать модуль os узла для сохраните путь к кешу. Он существует в соответствующем системном каталоге, поэтому файл кеша все еще будет существовать после обновления.
Пример кода выглядит следующим образом:
export const writeFile = (path: string, fileName: string, file: object, system: boolean = true) => {
const rePath = system ? `${os.homedir()}/${path}` : path
loggerInfo(rePath)
try {
fs.outputJsonSync(`${rePath}/${fileName}`, file)
loggerSuccess('Writing file successful!')
} catch (err) {
loggerError(`Error writing file from disk: ${err}`);
}
}
Как показано на рисунке выше, вы можете видеть, что большинство программ хранит кеш в системном каталоге, поэтому конфигурацию кеша можно использовать в обычном режиме после обновления или удаления и переустановки.
Определение версии
При регистрации плагина мы также использовалиlatest-version
Определите, есть ли версия в npm, чтобы определить, можно ли нормально загрузить пакет npm.Его собственная функция заключается в том, чтобы определить, является ли пакет npm последним.Если он не самый последний, вы можете обновить текущую версию.
При этом можно опционально проверить версию при старте проекта, например, когда появится версия npm пакетаbreak change, вы можете продолжать использовать функцию только путем принудительного обновления, но эта конфигурация зависит от текущих потребностей бизнеса, например, в случае, когда основное обновление встроенной команды можно использовать только после обновления CLI.
import { loggerInfo, loggerWarring } from '@/util';
const packageInfo = require('../../package.json');
import latestVersion from 'latest-version';
const parseVersion = (ver: string) => {
return ver.split('.').toString()
}
export const checkVersion = async () => {
const latestVer = await latestVersion('@boty-design/fe-cli');
if (parseVersion(latestVer) > parseVersion(packageInfo.version)) {
loggerWarring(`The current version is the : ${latestVer}`)
} else {
loggerInfo('The current version is the latest:')
}
}
напиши в конце
На данный момент интерфейс командной строки завершил функцию загрузки пользовательских подключаемых модулей.Метод может быть немного простым, но функция по-прежнему удовлетворяет.Студенты, у которых есть идеи на более позднем этапе, могут оптимизировать его (срочная работа - все демонстрационные типа, там много чего, поэтому код всего CLI пока очень сырой, там еще много деталей, которые можно тщательно отшлифовать).
Весь CLI-плагин написан в свободное время, на самом деле, как и у большинства разработчиков, у меня есть работа в течение дня, я очень занят, и мне не избежать сверхурочной работы, инфраструктура вся делается вовремя, поэтому первая версия должна быть грубым и пригодным для использования. , но когда все больше и больше людей будут его использовать и выдвигать больше функциональных требований, он начнет итерировать этот CLI.В итеративном процессе будет много рефакторинга.. Например, когда CLI разрабатывался ранее, конфигурация кеша существовала в корневом пути проекта CLI, и существовала скрытая опасность инвалидации кеша после обновления проекта. системный путь.
Однако в процессе постепенного улучшения функций эффект повышения эффективности и снижения затрат будет становиться все более и более очевидным, а ваши личные способности и влияние в команде также будут в определенной степени улучшаться. возможность возглавить работу инфраструктуры.Конечно, большая часть этой возможности зависит от конкретной ситуации команды и бизнеса.
Но в процессе выДизайн продукта, качество кода, деталиКогда у вас будет больше мыслей и инсайтов, у вас не будет глубокого понимания некоторых вещей, если вы не сделаете это сами.Если у вас нет лучших идей, целей и возможностей для упражнений, вы можете попробовать разработать CLI в качестве отправной точки.
Весь исходный код загружен наBOTY-DESIGN, если у вас есть какие-либо предложения или вопросы, пожалуйста, добавьте WeChatcookieboty, давайте исследовать и учиться вместе.