Вступ до сценаріїв NPM

Сценарії NPM є одними з найулюбленіших функцій NPM. Вони прості. Вони зменшують потребу в інструментах. Отже, вони зменшують кількість файлів конфігурації та інших речей, за якими потрібно стежити. І вони дуже універсальні. Вони також дозволяють автоматизувати багато загальних завдань. деякі з них перераховані в кінці статті.

Без зайвих сумнівів, давайте зануримось у сценарії NPM!

Що таке сценарії NPM?

Сценарії NPM - це, ну, скрипти. Ми використовуємо сценарії для автоматизації повторюваних завдань. Наприклад, побудова вашого проекту, зменшення файлів каскадних таблиць стилів (CSS) та JavaScript (JS). Скрипти також використовуються для видалення тимчасових файлів, папок тощо. Є багато способів це зробити - ви можете написати bash / batch скрипти або скористатися програмою запуску завдань, такою як Gulp або Grunt. Однак багато людей переходять до сценаріїв NPM за їх простоту та універсальність. Вони також пропонують можливість мати менше інструментів для вивчення, використання та відстеження.

Тепер, коли ми маємо (деяке) уявлення про те, що таке сценарії NPM та що вони можуть зробити для нас, давайте напишемо деякі!

Об'єкт сценаріїв у package.json

Більша частина нашої роботи відбуватиметься у файлі package.json, який NPM використовує як своєрідний маніфест. Це файл, який створюється під час запускуnpm init.

Ось зразок файлу package.json:

{ "name": "super-cool-package", "version": "1.0.0", "scripts": { ... }, "dependencies": { ... } "devDependencies": { ... } }

Якщо ви працювали з NodeJS та NPM, ви будете знайомі з файлом package.json. Зверніть увагу на scriptsоб’єкт у файлі. Сюди йтимуть наші сценарії NPM. Сценарії NPM записуються як звичайні пари ключ-значення JSON, де ключ - це ім'я сценарію, а значення містить сценарій, який потрібно виконати.

Ось, мабуть, найпопулярніший сценарій NPM (і це також особливий тип сценарію):

"scripts": { "start": "node index.js", ...}

Ви, напевно, бачили це безліч разів у файлах package.json. І ви, мабуть, знаєте, що npm startдля виконання сценарію ви можете ввести текст . Але цей приклад ілюструє перший важливий аспект сценаріїв NPM - це просто термінальні команди. Вони працюють в оболонці ОС, на якій вони виконуються. Тож це може бути bash для Linux та cmd.exe для Windows.

На даний момент ви можете бути зовсім не вражені. Але продовжуйте читати, щоб побачити, наскільки насправді потужні сценарії NPM.

Спеціальні сценарії

Сценарій, який ми щойно побачили, є одним із “спеціальних” сценаріїв NPM. Ви можете виконати його, просто ввівши текст npm start. Це сценарії з іменами, які NPM розпізнає і надає їм особливого значення. Наприклад, ви можете написати сценарій з назвою prepublish. NPM виконає сценарій перед тим, як пакунок буде упаковано та опубліковано, а також під час npm installлокального запуску без будь-яких аргументів. Детальніше про такі сценарії тут.

Але NPM також дозволить вам визначити власні власні сценарії. Саме тут починає проявлятися сила сценаріїв NPM.

Давайте розглянемо супер базовий власний сценарій NPM, який виводить на приставку “привіт світ”. Додайте це до об’єкта сценаріїв вашого файлу package.json:

"say-hello": "echo 'Hello World'"

Об'єкт сценаріїв у вашому файлі package.json повинен виглядати так:

..."scripts": { "start": "node index.js", "say-hello": "echo 'Hello World!'"}

А тепер спробуйте запустити npm say-hello. Не працює? Це пояснюється тим, що користувацьким сценаріям NPM повинен передувати один run-scriptабо runдля їх правильного виконання. Спробуйте запустити npm run-script say-helloабо npm run say-hello. На консолі написано: “Привіт, світе!”! Ми написали свій перший сценарій NPM!

Ось коротка порада - щоб запобігти виведенню журналів NPM за замовчуванням на консоль під час виконання сценарію, додайте --silentпрапор. Ось як би виглядала ваша команда:

npm run --silent say-hello

Виклик сценаріїв NPM у межах інших сценаріїв NPM

Один мінус використання сценаріїв NPM проявляється, коли ваш сценарій досить складний (і довгий). Ця проблема ускладнюється тим, що специфікація JSON не підтримує коментарі. Є кілька способів обійти цю проблему. Один із способів - розділити свій сценарій на невеликі одноцільові сценарії, а потім викликати їх у межах інших сценаріїв NPM. Спосіб виклику сценарію NPM всередині іншого є простим. Змініть свій scriptsоб’єкт так, щоб він виглядав так:

"scripts": { "say-hello": "echo 'Hello World'", "awesome-npm": "npm run say-hello && echo 'echo NPM is awesome!'"}

Оскільки сценарії NPM виконуються в оболонці, виклики npm run say-helloв іншому сценарії NPM майже інтуїтивно зрозумілі.

Для тих з вас, хто не дуже добре володіє командами терміналу, &&в сценарії використовується розділення двох команд. Таким чином, друга команда виконується після успішного виконання першої команди.

Тепер, коли ви запускаєте npm run awesome-npm, скрипт say-hello виконується спочатку, виводячи на консоль “Hello World”, а потім частина сценарію після &&, яка виводить “NPM awesome!”

Ось варіант використання, де це може бути корисним. Припустимо, ви автоматизуєте процес складання своєї програми. Скажімо, ви використовуєте Webpack як пакет, і ваш код розповсюдження потрапляє в каталог під назвою “dist”.

Ви можете почати з очищення каталогу. Це можна зробити, видаливши його вміст або видаливши сам каталог, а потім зробивши його знову. Давайте підемо з останнім підходом. Ваша команда може виглядати приблизно так:

rm -r dist && mkdir dist
Зверніть увагу, що тут використовуються команди bash. Далі в цій статті ви дізнаєтеся, як писати міжплатформні сценарії NPM.

Після цього ви можете викликати пакет, виконавши webpackкоманду.

Ви можете виконувати ці команди послідовно, використовуючи &&оператор. Однак для демонстрації та модульності розберемо це на два сценарії NPM, які викликають один одного.

Ось як виглядатиме об’єкт сценаріїв у цьому випадку використання:

"scripts": { ... "clean": "rm -r dist && mkdir dist", "build": "npm run clean && webpack"}

Ось тобі! Як розділити більш складне завдання на менші сценарії NPM.

Виклик сценаріїв оболонки та вузла

Іноді вам може знадобитися писати сценарії набагато складніші, ніж ті, які можна досягти за допомогою 2-3 команд. Коли виникає така ситуація, одним із рішень є написання скриптів bash або JS (або скриптів на будь-якій вподобаній мові сценаріїв) і виклик їх із сценаріїв NPM.

Давайте швидко напишемо скрипт bash, який вітає вас. Створіть файл, який називається hello.shу вашому кореневому каталозі, і вставте в нього цей код:

#!/usr/bin/env bash
# filename: hello.shecho "What's your name?"read nameecho "Hello there, $name!"

Це простий сценарій, який повторює ваше ім’я. Тепер змініть package.jsonфайл так, щоб scriptsоб'єкт мав такий рядок коду:

"bash-hello": "bash hello.sh"

Тепер, коли ви біжите npm run bash-hello, він запитує ваше ім’я, а потім вітається з вами! Блискуче.

Ви можете зробити те ж саме зі сценаріями JS, що запускаються за допомогою node. Перевага цього підходу полягає в тому, що цей сценарій буде незалежним від платформи, оскільки він використовує node для запуску. Ось трохи більш складний скрипт JS для додавання двох цілих чисел, отриманих як аргументи командного рядка (помістіть це у файл з іменем add.js):

// add.js// adds two integers received as command line arguments
function add(a, b) { return parseInt(a)+parseInt(b);}
if(!process.argv[2] || !process.argv[3]) { console.log('Insufficient number of arguments! Give two numbers please!');}
else { console.log('The sum of', process.argv[2], 'and', process.argv[3], 'is', add(process.argv[2], process.argv[3]));}
Об'єкт process.argv містить аргументи командного рядка, надані сценарію. Перші два елементи, process.argv[0]і process.argv[1], зарезервовані вузлом. Таким чином, process.argv[2]і process.argv[3]ви можете отримати доступ до аргументів командного рядка.

Now add this line to the scripts object of the package.json file:

"js-add": "node add.js"

Finally, run the script as an npm script by giving it two numbers as command line arguments:

npm run js-add 2 3

And viola! The output is

The sum of 2 and 3 is 5

Brilliant! Now we’re capable of writing much more powerful scripts and leveraging the power of other scripting languages.

Pre and Post Hooks

Remember how we talked about a special npm script called prepublish that runs before you publish your package? Such a functionality can be achieved with custom scripts too. We’ve discussed one way to do this in the previous section. We can chain commands using the &&operator, so if you wanted to run script-1 before script-2, you would write:

"script-2": "npm run script-1 && echo 'I am script-2'"

However, this makes our scripts a little dirty. This is because the core functionality of the script is reflected only in the second part of the command (after the && ). One way to write clean scripts is to use pre and post hooks.

Pre and post hooks are exactly what they sound like — they let you execute scripts before and after you call a particular script. All you have to do is define new scripts with the same name as your main script. Yet these are prefixed with “pre” or “post” depending on whether the script is executed before the main script or after it.

Let’s look at our say-hello script again. Say we want to execute the command echo 'I run before say-hello' before say-hello and echo 'I run after say-hello' after say-hello. This is what your scripts object would look like:

"scripts": { "say-hello": "echo 'Hello World'", "presay-hello": "echo 'I run before say-hello'", "postsay-hello": "echo 'I run after say-hello'" }

The “pre” and “post” before the script names tell npm to execute these before and after the script called say-hello respectively.

Now, when you run npm run say-hello, the output of all three scripts shows up in order! How cool is that?

Since all three scripts output to the console and the NPM logs clutter the output, I prefer using the -silent flag while running these. So your command would look like this:

npm run --silent say-hello

And here’s the output:

I run before say-helloHello WorldI run after say-hello

There you have it!

Let’s apply this knowledge to our build script example. Modify your package.json file so that it looks like this:

"scripts": { ... "clean": "rm -r dist && mkdir dist", "prebuild": "npm run clean" "build": "webpack"}

Now our scripts look much cleaner. When you run npm run build, prebuildis called because of the “pre” hook, which calls clean, which cleans up our dist directory for us. Sweet!

Making Our Scripts Cross-Platform

There is one drawback of writing terminal/shell commands in our scripts. This is the fact that shell commands make our scripts platform dependently. This is perhaps what draws our attention to tools like Gulp and Grunt. If your script is written for Unix systems, chances are, it won’t work on Windows, and vice versa.

The first time I used NPM scripts, which called other bash/batch scripts, I thought of writing two scripts per task. One for Unix and one for the Windows command line. This approach may work in use cases where the scripts aren’t that complex and there aren’t many scripts. However, it quickly becomes clear that they are not a good solution to the problem. Some of the reasons behind this are:

  • You have another thing to keep track of that distracts you from your primary task of working on the application. Instead, you end up working in the development environment.
  • You’re writing redundant code — the scripts you write are very similar and accomplish the same task. You’re essentially rewriting code. This violates one of the fundamental principles of coding — DRY: Don’t Repeat Yourself.

So how do we get around this? There are three approaches that you may use:

  1. Use commands that run cross-platform: Many useful commands are common to Unix and Windows. If your scripts are simple, consider using those.
  2. Use node packages: You can use node packages like rimraf or cross-env instead of shell commands. And obviously, you can use these packages in JS files if your script is large and complex.
  3. Використовуйте ShellJS: ShellJS - це пакет npm, який запускає команди Unix через Node. Отже, це дає вам можливість запускати команди Unix на всіх платформах, включаючи Windows.
Вищезазначені підходи були взяті з цієї блискучої статті Корі Хауса про те, чому він залишив Грунт та Галп для сценаріїв NPM. Стаття детально описує багато речей, не висвітлених у цій серії, і завершує переліком чудових ресурсів. Я точно рекомендую вам прочитати його, щоб глибше зрозуміти сценарії NPM.

Мало випадків використання сценаріїв NPM

Нарешті, можна багато чого зробити зі сценаріями NPM. Деякі випадки використання:

  • Зменшення / вирівнювання CSS / JavaScript
  • Автоматизація процесу збірки
  • Прив'язка коду
  • Стискання зображень
  • Автоматичне введення змін за допомогою BrowserSync

And a lot more. To learn about how to automate the above-mentioned tasks using NPM scripts, check out this brilliant article on the topic.

Bonus: Commander for Creating CLI Applications Using NodeJS

While we’re discussing NPM scripts and the CLI, I’d like to quickly tell you about a really cool package called commander. Commander allows you to create your own CLI applications. This isn’t really related to NPM scripts, but it’s a cool piece of technology to know. Check out the commander docs here or try one of these tutorials:

  • Build An Interactive Command-Line Application with Node.js — Scotch.io
  • Writing Command Line Applications in NodeJS — freeCodeCamp

Concluding Words

That is all for this article on using NPM scripts. I hope you’ve gained some insight on how you can integrate these into your own projects. This article is by no means an in-depth tutorial on NPM scripts. Hence I’d recommend you learn further both from other resources and from actually using NPM scripts in your own projects.

Also, do connect with me on GitHub and LinkedIn.

Happy Coding! :)