Въведение в 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 скрипт!

Ето един бърз съвет - за да предотвратите извеждането на регистрационните файлове по подразбиране към конзолата, когато изпълнявате скрипт, добавете --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 е страхотен!“

Ето един случай на употреба, където това може да е полезно. Да предположим, че автоматизирате процеса на изграждане на вашето приложение. Да приемем, че използвате Webpack като пакет и вашият код за разпространение отива в директория, наречена “dist”.

Може да започнете с почистване на директорията. Това може да се направи, като изтриете съдържанието му или изтриете самата директория и след това я направите отново. Нека да продължим с последния подход. Вашата команда може да изглежда по следния начин:

rm -r dist && mkdir dist
Имайте предвид, че това използва команди bash. Ще научите как да пишете междуплатформени NPM скриптове по-късно в тази статия.

След това можете да извикате пакета, като изпълните webpackкомандата.

Можете да изпълнявате тези команди последователно, като използвате &&оператора. За демонстрация и модулност обаче, нека разделим това на два NPM скрипта, които се извикват взаимно.

Ето как би изглеждал обектът на скриптове в този случай на употреба:

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

Ето го! Как да разделите по-сложна задача на по-малки NPM скриптове.

Извикване на Shell и Node скриптове

Понякога може да се наложи да пишете скриптове далеч по-сложни от тези, които могат да бъдат постигнати с 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.
Горните подходи бяха взети от тази брилянтна статия на Кори Хаус за това защо той напусна Grunt и Gulp за 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! :)