Используйте zx.js вместо Shell

от автора

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

Код инструмента zx доступен на github.

Что такое zx.js и почему его используют?

Командная оболочка Bash хороша, но когда дело доходит до написания скриптов, люди часто выбирают более удобный язык программирования, и JavaScript прекрасно для этого подходит. Перед началом работы стандартная библиотека Node.js требует множества дополнительных операций, таких как инсталляция и ее внедрение. zx обеспечивает обертку модулю child_process, которая экранирует параметры и предоставляет смердженные значения по умолчанию.

Сначала рассмотрим официальный пример:

#!/usr/bin/env zx  // From https://github.com/google/zx#-zx await $`cat package.json | grep name`    let branch = await $`git branch --show-current`   await $`dep deploy --branch=${branch}`    await Promise.all([     $`sleep 1; echo 1`,     $`sleep 2; echo 2`,     $`sleep 3; echo 3`,   ])    let name = 'foo bar'   await $`mkdir /tmp/${name}`

Официальный пример

Синтаксис JavaScript в приведенном выше примере может показаться немного странным. Он использует фичу языка, которая называется тегированные шаблонные литералы (tagged template literals).

Но это же круто, правда? Так что давайте начнем!

Инсталляция

// Глобальная инсталляция. // Также вы можете установить его отдельно в своем проекте. npm i zx -g

Требование:

Убедитесь, что версия вашего node >= 16.00.0.

Принцип работы zx.js

Он предоставляет функции, которые оборачивают процедуру создания дочерних процессов и обработку stdout и stderr из них.

Использование

  • Для быстрого тестирования скрипта можно использовать символ пайплайна

$ echo "console.log(await (await fetch('http://orange.tw')).text())" | zx $ fetch http://orange.tw 183.133.12.121 Your country
  • Другой способ — разработать скрипт в проекте, как мы часто делаем.

Сначала инициализируйте проект,

mkdir zx-demo cd zx-demo touch index.mjs npm init -y  // Note: the zx documentation suggests installing the library globally with npm.  // By installing it as a local dependency of our project instead,  // we can ensure that zx is always installed, as well as control the version that our shell scripts use. npm i zx -D

Основной файл должен содержать следующие заголовки файлов:

#!/usr/bin/env zx

Сначала нужно добавить разрешения на выполнение, а затем запустить скрипт:

chmod +x ./index.mjs   ./index.mjs    // Or use this command  zx ./index.mjs

Теперь он может отображать какое-то содержимое, zx.js предоставляет много черной магии, у него есть встроенные fetch, question и асинхронные операции (круто), и теоретически он способен выполнять shell и другие скрипты типа tree и прочие команды, установленные самостоятельно, что очень мощно.

Дальше давайте имплементируем инструмент командной строки, который обычно используется для создания библиотеки компонентов!

Инструмент командной строки

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

Сначала необходимо создать проект ноды в соответствии с приведенной выше частью, а затем создать соответствующий каталог/файл, как показано на рисунке. После завершения операции структура ваших каталогов должна выглядеть следующим образом. Не забудьте создать новый файл index.ts в каталоге компонентов (игнорируйте файл протокола и каталог .vscode)

Инициализация проекта

  1. Для начала нам нужно создать первый файл шаблона, который является компонентом React и по умолчанию экспортирует тип Props, и, в итоге, генерирует содержимое каталога и файла.

export default (fileName) => ({   content: ` // Generated with index.js, Assume this is a react project import React from "react"; export interface I${fileName}Props {} const ${fileName}: React.FC<I${fileName}Props> = () => {   return (     <div>{/** Todo... */}</div>   ); } export default ${fileName}; `,   suffix: `tsx`, });
  1. Экспорт файла шаблона

import componentMain from "./component-main.mjs";  const templates = [componentMain];  export default templates;
  1. Нам нужен основной файл, который экспортирует все компоненты (например, Button, Select, Card); это является хорошей практикой программирования.

#!/usr/bin/env zx  import _fs from "fs"; import { chalk } from "zx";  const fs = _fs.promises;  /**  * @description This function is subduquered according to the file name generated by `npm run generate your filename`,  * then automatically injects imported import export in src/components/index.js.  *  * @param { string } directoryName  * @returns { void }  */ const additionalEntryContent = async (directoryName) => {   const originalFile = "./src/components/index.ts";    // Read original file content   const entryFileContent = await fs.readFile(originalFile, "utf-8");    // Additional content   fs.writeFile(     originalFile,     entryFileContent.concat(       ` export type { I${directoryName}Props } './${directoryName}'; export { default as ${directoryName} } from "./${directoryName}";\n`     )   );    console.log(     chalk.green(`Successfully additional content in: ${originalFile}`)   ); };  export default additionalEntryContent;
  1. Напишите основной логический код в файле index.mjs, который отвечает за получение информации о параметрах командной строки, вводимой пользователем, определение существования каталога, создание каталога и окончательное обновление каждого файла.

#!/usr/bin/env zx  import { $, chalk } from "zx"; import fs from "fs";  import templates from "./scripts/templates/index.mjs"; import additionalEntryContent from "./scripts/additional-entry.mjs";  $.verbose = false;  const directoryName = process.argv[2]; if (!directoryName) {   console.error(     chalk.red("[Error]: Create file error, please supply a valid directoryName")   );   process.exit(1); }  // The Directory address of the generated file const componentDirectory = `./src/components/${directoryName}`;  if (fs.existsSync(componentDirectory)) {   console.error(chalk.red(`Directory ${directoryName} already exists`));   process.exit(1); }  fs.mkdirSync(componentDirectory);  try {   const generatedTemplates = templates.map((template) =>     template(directoryName)   );    generatedTemplates.forEach((template) => {     fs.writeFileSync(       `${componentDirectory}/index.${template.suffix}`,       template.content     );   });    console.log(chalk.green("Successfully created directory:", directoryName));    // Add the context to the imported content in Index.js   additionalEntryContent(directoryName); } catch (error) {   console.error(error);   process.exit(1); }
  1. Приступаем к созданию компонента, открываем терминал, например, мы хотим создать компонент Button.

Готово
Готово

Успешно, мы создали компонент Button, и экспортируемый связанный код автоматически загружается в components/index.ts, отлично.


Перевод статьи подготовлен в рамках специализации «Fullstack Developer».


ссылка на оригинал статьи https://habr.com/ru/company/otus/blog/670112/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *