Pull to refresh
1417.43
OTUS
Цифровые навыки от ведущих экспертов

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

Reading time5 min
Views5.1K
Original author: Tomoe Li

В этой статье мы изучим, что такое 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".

Tags:
Hubs:
Total votes 11: ↑6 and ↓5+1
Comments8

Articles

Information

Website
otus.ru
Registered
Founded
Employees
101–200 employees
Location
Россия
Representative
OTUS