Скрипты Node: от основ до продвинутого уровня

Раздел: Backend -> Node.js (базовый)

Основные подходы к созданию скриптов Node.js

Как реализовать утилиту для поиска строк в файлах с использованием аргументов командной строки?

Эффективный способ заключается в применении встроенных модулей fs/promises и process.argv. Это позволяет быстро написать скрипт, который принимает путь к файлу и искомую строку, читает файл и выводит совпадения. Такой подход широко используется для администрирования и обработки логов.

const fs = require('fs/promises');
const [,, filePath, searchWord] = process.argv;
(async () => {
  try {
    const data = await fs.readFile(filePath, 'utf8');
    const lines = data.split('\n').filter(line => line.includes(searchWord));
    lines.forEach(line => console.log(line));
  } catch (err) {
    console.error('Ошибка:', err.message);
  }
})();

Node js https (https в node.js)

Пояснение шагов:

  • Импорт модуля fs/promises для асинхронной работы с файлами.
  • Деструктуризация process.argv для получения аргументов (первые два элемента - node и путь к скрипту, остальные - пользовательские).
  • Обёртка в асинхронную IIFE для использования await.
  • Чтение файла, разбивка на строки, фильтрация по include.
  • Вывод результата в консоль, обработка ошибок через try/catch.
Типичные ошибки: забывают проверять количество аргументов (если их меньше двух, возникнет ошибка при деструктуризации). Также возможны проблемы с кодировкой файла, если она не UTF-8. Рекомендуется добавить проверки и обрабатывать ошибки через try/catch.

Как выполнить простой скрипт без параметров?

Самый простой вариант - создать JavaScript файл с любым кодом и запустить его командой node. Этот способ подходит для быстрых тестов, проверки идей и одноразовых операций.

// hello.js
console.log('Привет, Node.js!');
console.log('Текущее время:', new Date().toLocaleString());

Node js lts (версия node.js lts)

Запуск: node hello.js. Вывод будет содержать строки приветствия и текущую дату. Никакие дополнительные модули не требуются.

Ошибки: часто забывают установить Node.js или указывают неправильный путь к файлу. Следует убедиться, что файл существует и синтаксис корректен.

Как передавать именованные параметры в скрипт?

Для повышения удобства можно обрабатывать флаги вручную, анализируя process.argv. Этот метод полезен, когда не хочется подключать внешние библиотеки.

const args = process.argv.slice(2);
const params = {};
for (let i = 0; i < args.length; i += 2) {
  const key = args[i].replace(/^--/, '');
  params[key] = args[i + 1];
}
console.log('Полученные параметры:', params);
// Пример запуска: node script.js --name John --age 30

Node js npm (менеджер пакетов npm в node.js)

Скрипт разбирает пары --ключ значение. Рекомендуется следить, чтобы чётное количество аргументов и значения не начинались с --.

Если значение содержит пробел, его нужно заключать в кавычки при запуске. Также возможны ошибки, если забыть указать значение для последнего ключа. Рекомендуется добавить проверки.

Как использовать сторонние npm пакеты для парсинга аргументов?

Библиотеки yargs или commander предоставляют мощные средства для описания интерфейса командной строки. Они автоматически генерируют справку, проверяют типы и поддерживают вложенные команды. Этот вариант идеален для серьёзных утилит.

// установка: npm install yargs
const yargs = require('yargs/yargs');
const { hideBin } = require('yargs/helpers');
const argv = yargs(hideBin(process.argv))
  .option('name', { alias: 'n', type: 'string', demandOption: true, describe: 'Имя пользователя' })
  .option('greeting', { alias: 'g', type: 'string', default: 'Привет' })
  .argv;
console.log(`${argv.greeting}, ${argv.name}!`);

Node js scripts (скрипты node.js)

Запуск: node greet.js --name Мир. Выведет "Привет, Мир!". yargs обрабатывает ошибки и выводит справку при --help.

Возможны конфликты версий yargs, особенно с ESM. Рекомендуется использовать yargs в CommonJS, либо подключать соответствующие синтаксисы.

Как читать и записывать файлы асинхронно?

Для работы с файлами используется модуль fs (или fs/promises для promise-based API). Это необходимо для скриптов, которые обрабатывают данные, конфигурации или логи.

const fs = require('fs/promises');
async function processFile() {
  try {
    const content = await fs.readFile('./input.txt', 'utf8');
    const transformed = content.toUpperCase();
    await fs.writeFile('./output.txt', transformed);
    console.log('Файл обработан');
  } catch (err) {
    console.error('Ошибка:', err);
  }
}
processFile();

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

Часто забывают указывать кодировку 'utf8', что приводит к получению буфера. Также возможны ошибки доступа, если файл занят или нет прав. Рекомендуется использовать try/catch.

Как запускать системные команды из скрипта?

Модуль child_process позволяет выполнять внешние программы и получать их вывод. Это пригодится для интеграции с Bash, git, Docker и другими инструментами.

const { exec } = require('child_process');
exec('ls -la', (error, stdout, stderr) => {
  if (error) {
    console.error(`Ошибка: ${error.message}`);
    return;
  }
  if (stderr) {
    console.error(`Stderr: ${stderr}`);
  }
  console.log('Вывод:', stdout);
});

Функция exec запускает команду в shell и возвращает результат в колбеке. Для больших объёмов данных лучше использовать spawn.

Опасность инъекций: не следует передавать непроверенные пользовательские данные напрямую в exec. Лучше использовать spawn с массивом аргументов. Также необходимо управлять временем выполнения (timeout).

Как настроить псевдонимы команд в package.json?

В поле scripts файла package.json можно определить сокращения для часто используемых команд. Это упрощает работу в команде и стандартизирует запуск.

{
  "scripts": {
    "start": "node server.js",
    "dev": "nodemon server.js",
    "clean": "rm -rf dist && mkdir dist",
    "greet": "node greet.js --name"
  }
}

Теперь команды npm start, npm run dev, npm run clean будут выполнять указанные действия. Параметры можно передавать через -- (npm run greet -- World).

Синтаксис npm run требует осторожности с пробелами и кавычками. Если скрипт использует аргументы, иногда лучше вызывать напрямую node script.js.

Продвинутые примеры скриптов Node.js

Пример 1: Копирование файлов с прогрессом через потоки и yargs

Пример
// copy.js
const fs = require('fs');
const path = require('path');
const yargs = require('yargs/yargs');
const { hideBin } = require('yargs/helpers');

const argv = yargs(hideBin(process.argv))
  .option('source', { alias: 's', type: 'string', demandOption: true, describe: 'Исходный файл' })
  .option('dest', { alias: 'd', type: 'string', demandOption: true, describe: 'Целевой файл' })
  .argv;

const sourcePath = path.resolve(argv.source);
const destPath = path.resolve(argv.dest);

const readStream = fs.createReadStream(sourcePath);
const writeStream = fs.createWriteStream(destPath);
let totalBytes = 0;

readStream.on('data', (chunk) => {
  totalBytes += chunk.length;
  process.stdout.write(`\rСкопировано ${totalBytes} байт`);
});

readStream.pipe(writeStream);

writeStream.on('finish', () => {
  console.log('\nКопирование завершено');
});

readStream.on('error', (err) => {
  console.error('Ошибка чтения:', err.message);
});
writeStream.on('error', (err) => {
  console.error('Ошибка записи:', err.message);
});
$ node copy.js -s bigfile.mp4 -d backup.mp4
Скопировано 1024000 байт
Копирование завершено

Пояснение: используются потоки для эффективной обработки больших файлов, отображается прогресс копирования в реальном времени.

Пример 2: Мониторинг изменений в папке с chokidar

Пример
// watcher.js
const chokidar = require('chokidar');
const path = require('path');

const watchDir = process.argv[2] || '.';
const watcher = chokidar.watch(watchDir, { persistent: true });

watcher
  .on('add', filePath => console.log(`Файл добавлен: ${path.relative('.', filePath)}`))
  .on('change', filePath => console.log(`Файл изменён: ${path.relative('.', filePath)}`))
  .on('unlink', filePath => console.log(`Файл удалён: ${path.relative('.', filePath)}`));

console.log(`Наблюдение за каталогом "${watchDir}" запущено...`);
$ node watcher.js ./logs
Наблюдение за каталогом "./logs" запущено...
Файл добавлен: error.log
Файл изменён: error.log

Пояснение: скрипт отслеживает появление, изменение и удаление файлов в указанной папке, полезно для автоматизации при разработке.

Пример 3: Генерация тестовых данных с faker

Пример
// seed.js
const { faker } = require('@faker-js/faker');
const fs = require('fs/promises');

const COUNT = 100;
const users = Array.from({ length: COUNT }, (_, i) => ({
  id: i + 1,
  name: faker.person.fullName(),
  email: faker.internet.email(),
  createdAt: faker.date.past().toISOString()
}));

(async () => {
  await fs.writeFile('users.json', JSON.stringify(users, null, 2));
  console.log(`Сгенерировано ${COUNT} пользователей`);
})();
$ node seed.js
Сгенерировано 100 пользователей

Пояснение: создаётся файл с фиктивными данными пользователей для тестирования баз данных или API.

Пример 4: Пакетная конвертация изображений с sharp

Пример
// convert.js
const sharp = require('sharp');
const path = require('path');
const fs = require('fs/promises');

const inputDir = './images';
const outputDir = './thumbnails';

(async () => {
  await fs.mkdir(outputDir, { recursive: true });
  const files = await fs.readdir(inputDir);
  for (const file of files) {
    if (file.endsWith('.jpg') || file.endsWith('.png')) {
      const inputPath = path.join(inputDir, file);
      const outputPath = path.join(outputDir, `thumb_${file}`);
      await sharp(inputPath)
        .resize(200, 200)
        .toFile(outputPath);
      console.log(`Обработан: ${file}`);
    }
  }
  console.log('Конвертация завершена');
})();
$ node convert.js
Обработан: photo1.jpg
Обработан: photo2.png
Конвертация завершена

Пояснение: скрипт находит все изображения JPG и PNG в папке, уменьшает их до 200x200 пикселей и сохраняет в другую папку.

Пример 5: Выполнение удалённой команды по SSH

Пример
// ssh-exec.js
const { Client } = require('ssh2');
const conn = new Client();
conn.on('ready', () => {
  conn.exec('uptime', (err, stream) => {
    if (err) throw err;
    stream.on('data', (data) => {
      console.log('STDOUT: ' + data);
    });
    stream.stderr.on('data', (data) => {
      console.log('STDERR: ' + data);
    });
    stream.on('close', () => conn.end());
  });
}).connect({
  host: 'example.com',
  username: 'user',
  privateKey: require('fs').readFileSync('/path/to/key')
});
$ node ssh-exec.js
STDOUT:  10:30:15 up 30 days,  2:15,  1 user,  load average: 0.00, 0.01, 0.05

Пояснение: скрипт подключается к удалённому серверу по SSH, выполняет команду uptime и выводит результат. Полезно для автоматизации администрирования.

Скрипты Node.js - comments

En
Node js scripts (javascript)