
У опытного программиста, сталкивающегося с новой технологией для решения конкретной прикладной задачи, сразу возникает множество практических вопросов. Как правильно установить платформу? Где и что будет лежать после установки? Как создать каркас проекта, как он будет структурирован? Как разбивать код на модули? Как добавить библиотеку в проект? Где вообще взять готовую библиотеку, которая делает то, что нужно? Как и в чём отлаживать код? Как написать модульный тест?
Ответы на эти вопросы можно при желании легко найти в сети, но придётся перечитать дюжину статей, и на каждый вопрос ответов будет, скорее всего, несколько. Некоторое время назад мне понадобилось написать небольшой туториал по node.js, который бы позволил быстро запустить разработку и познакомить новых программистов в проекте с этой технологией. Рассчитан он на опытных Java-разработчиков, которые и язык JavaScript хорошо знают, но node.js как платформа для бэкэнда для них в новинку.
Думаю, что данная статья будет полезна не только разработчикам из мира Java, но и всем, кто начинает работу с платформой node.js.

Установка и настройка
Установка node и npm
Windows
Установка node.js под Windows производится с помощью msi-инсталлятора. Для его загрузки нужно перейти на сайт https://nodejs.org и щёлкнуть «Install». После скачивания инсталлятора (файл с именем вида node-v0.12.4-install.msi) необходимо запустить его и следовать инструкциям по установке.

По умолчанию под Windows node.js устанавливается в папку c:\Program Files\nodejs. Также по умолчанию устанавливаются все компоненты (собственно node.js, пакетный менеджер npm, ссылка на документацию; кроме того, путь к node и npm прописывается в переменную среды PATH). Желательно убедиться, что все компоненты установки выбраны.

OS X
В OS X проще всего установить node через менеджер пакетов brew. Для этого необходимо выполнить команду:
> brew install node
Node установится в папку /usr/local/Cellar/<версия>/node с постоянным симлинком /usr/local/opt/node/.
Ubuntu (x64)
Для установки последней ветки (0.12) лучше скачать дистрибутив с сайта:
wget http://nodejs.org/dist/v0.12.4/node-v0.12.4-linux-x64.tar.gz
sudo tar -C /usr/local --strip-components 1 -xzf node-v0.12.4-linux-x64.tar.gz
Дистрибутив распакуется в папку /usr/local в подпапки bin, include, lib и share.
Проверка установки
Для проверки корректности установки можно запустить в командной строке node и npm с параметром --version:
> node --version
v0.12.4
> npm --version
2.10.1
Установка плагина в IntelliJ IDEA
Запустим IntelliJ IDEA, зайдём в настройки.

Найдём раздел Plugins и щёлкнем «Install JetBrains Plugin...»

Найдём в списке плагин NodeJS, щёлкнем по кнопке «Install Plugin». По окончании загрузки кнопка превратится в «Restart IntelliJ IDEA» — щёлкнем её для перезагрузки среды.

После перезагрузки зайдём в настройки и найдём раздел Languages & Frameworks -> Node.js and NPM. Убедимся, что в разделе «Node interpreter» указана ссылка на установленный исполняемый файл node.

В разделе «Sources of node.js Core Modules» щёлкнем кнопку «Configure». В появившемся окне выберем «Download from the Internet» и щёлкнем «Configure», при этом скачаются и проиндексируются исходники node.js. Это позволит просматривать исходники при разработке.

В разделе packages отображаются глобально установленные пакеты (см. раздел «Глобальные пакеты»). В этом окне можно добавлять, удалять и обновлять эти пакеты. Если рядом с именем пакета отображается синяя стрелочка, значит, доступно обновление. Глобально лучше устанавливать только пакеты-утилиты.
Первые шаги
Пишем «Hello World»
Создадим файл app.js, который формирует и выводит соответствующую строчку в консоль:
// файл app.js
var greeting = 'hello';
greeting += ' world!';
console.log(greeting);
Запустим его командой:
> node app.js
hello world!
Используем REPL
Запустив команду node без аргументов, можно попасть в REPL-цикл, аналогичный браузерной JS-консоли. В нём можно выполнять и проверять фрагменты кода:
> node
> console.log('hello world!')
hello world!
undefined
> [1, 2, 3].reduce(function(sum, item){return sum + item}, 0)
6
Каждая выполненная строчка имеет возвращаемый результат, который также выводится в консоль. Функция console.log() не возвращает результата, поэтому после её вызова в консоли вывелось «undefined».
В REPL-консоли работает автодополнение по нажатию клавиши Tab. Например, если написать «console.» и нажать Tab, то отобразится список атрибутов и функций объекта console.
> console.
console.__defineGetter__ console.__defineSetter__
console.__lookupGetter__ console.__lookupSetter__
console.__proto__ console.constructor
console.hasOwnProperty console.isPrototypeOf
console.propertyIsEnumerable console.toLocaleString
console.toString console.valueOf
console.assert console.dir
console.error console.info
console.log console.time
console.timeEnd console.trace
console.warn
console.Console console._stderr
console._stdout console._times
> console.
Для выхода из консоли можно нажать Ctrl+D.
Работа с npm
Инициализация проекта
Для инициализации проекта выполним в каталоге будущего проекта команду npm init и введём необходимые данные в интерактивном режиме (можно просто нажимать Enter, так как предлагаются внятные настройки по умолчанию):
> npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.
See `npm help json` for definitive documentation on these fields and exactly what they do.
Use `npm install <pkg> --save` afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
name: (nodetest)
version: (1.0.0)
description: my first node application
entry point: (index.js) app.js
test command:
git repository:
keywords:
author:
license: (ISC)
About to write to ***\package.json:
{
"name": "nodetest",
"version": "1.0.0",
"description": "my first node application",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
Is this ok? (yes)
По окончании выполнения утилиты в текущем каталоге будет создан файл package.json, описывающий конфигурацию проекта. В нём же будет храниться информация о зависимостях проекта.
Добавление пакетов-зависимостей в проект
Чтобы установить зависимость в проект, используется команда npm install. При этом в текущем каталоге будет создана папка node_modules, в которую будет помещён загруженный пакет. Ключ --save означает, что информация об этой зависимости будет добавлена также в package.json. Например, установим пакет log4js для протоколирования:
> npm install --save log4js
log4js@0.6.25 node_modules/log4js
├── async@0.2.10
├── underscore@1.8.2
├── semver@4.3.4
└── readable-stream@1.0.33 (isarray@0.0.1, inherits@2.0.1, string_decoder@0.10.31, core-util-is@1.0.1)
После выполнения этой команды обнаружим, что в текущем каталоге появилась папка node_modules\open, а в файле package.json добавилась запись:
"dependencies": {
"log4js": "0.6.25"
}
Запись о зависимости можно добавить в файл package.json и вручную, но после этого необходимо выполнить npm install, чтобы загрузить указанную зависимость в каталог node_modules.
Глобальные пакеты
Пакеты можно устанавливать как в каталог проекта, так и глобально, тогда они будут видны для всех проектов. Как правило, глобально устанавливаются только пакеты, являющиеся утилитами, например, утилита управления зависимостями bower, сборщики gulp и grunt, генератор проектов на Express express-generator, и т.д.
Глобальные пакеты устанавливаются:
- В Windows 8 — в %USERPROFILE%\AppData\Roaming\npm\node_modules,
- В OS X — в /usr/local/lib/node_modules,
- В Ubuntu — в /usr/local/lib/node_modules.
Чтобы установить пакет глобально, команда npm выполняется с ключом -g:
npm install -g grunt
Работа в IntelliJ IDEA
Открытие проекта
Чтобы открыть проект на node.js, достаточно открыть папку, содержащую package.json.

Настройка конфигурации запуска
Для запуска и отладки в IntelliJ IDEA необходимо создать конфигурацию запуска. Для этого зайдём в Run -> Run Configurations, щёлкнем плюсик в левом верхнем углу и выберем node.js:

Заполним поля Name и JavaScript File:

Теперь можно запускать скрипт в обычном режиме и в режиме отладки с помощью соответствующих кнопок на панели инструментов:

Отладка
Для отладки необходимо запустить созданную конфигурацию в режиме Debug. При этом можно ставить брейкпойнты на строки, «шагать» по строкам, смотреть содержимое стека вызовов, значения переменных в текущем контексте и делать всё прочее, что ожидается от отладочного режима.

Модульность в node.js
В Java единицами модульности являются пакеты и классы. Единицей модульности в node.js является файл. Чтобы сделать импорт одного модуля в другой, используется модуль-локальная (т.е. неявно определённая в каждом модуле) функция require(). Стандартные модули или пакеты, установленные в node_modules, можно импортировать по простому имени:
var http = require('http');
В переменную http будет помещён объект, который был экспортирован модулем http.
Если требуется импортировать не стандартный модуль, а один из модулей проекта в другой, то аргумент для функции require() должен содержать размещение модуля относительно текущего модуля (не считая расширения .js), например:
// файл myproject/somedir/mymodule1.js
mymodule2 = require('../anotherdir/mymodule2');
mymodule2.fun();
// файл myproject/anotherdir/mymodule2.js
module.exports.fun = function() {
console.log('hello world!');
}
Всё, что объявлено в файле модуля, видно только внутри него — за исключением того, что мы явно экспортируем. Например, в отличие от JavaScript в браузере, область видимости переменной, объявленной на верхнем уровне, ограничена тем модулем, в котором она объявлена:
// файл mymodule.js
var enterprise = 'bloody';
Переменная enterprise будет видна только внутри модуля mymodule.js.
Чтобы экспортировать что-либо из модуля, можно использовать доступный в любом модуле атрибут module.exports, который по умолчанию содержит в себе пустой объект. Можно также использовать сокращённую ссылку на него — модуль-локальную переменную exports. Функция require(), которой передано имя нашего модуля, будет возвращать то, что мы поместили в module.exports. Соответственно, если мы поместим туда такой объект:
// файл mymodule.js
module.exports = {
fun: function() {
console.log('hello world!');
}
}
То именно его вернёт функция require, будучи вызванной в другом модуле:
// файл mymodule-client.js
mymodule = require('./mymodule');
mymodule.fun();
Полученный объект mymodule — это тот же самый объект с функцией fun, который был присвоен атрибуту module.exports в нашем модуле.
Однако подобным способом сделать экспорт не получится:
// файл mymodule.js
exports = {
fun: function() {
console.log('hello world!');
}
}
Это связано с тем, что из модуля всегда экспортируется атрибут module.exports. Заменив сокращённую ссылку exports на другой объект, мы не изменили этот атрибут. Сокращённая ссылка exports может быть использована только для экспорта каких-то отдельных функций или атрибутов:
// файл mymodule.js
exports.fun = function() {
console.log('hello world!');
}
// файл mymodule-client.js
require('./mymodule').fun();
Тестирование
Mocha
Для добавления модульного тестирования в проект лучше всего начать с фреймворка Mocha. Устанавливается он как глобальный npm-модуль:
npm install -g mocha
Протестируем модуль с простейшей функцией:
// файл mymodule.js
exports.fun = function(name) {
return 'Привет, ' + name + '!';
}
Тесты mocha по умолчанию размещаются в подпапке test:
// файл test/mymodule-test.js
var assert = require('assert');
var mymodule = require('../mymodule');
describe('mymodule', function() {
describe('#fun()', function() {
it('должна приветствовать пользователя, имя которого передано как аргумент', function() {
assert.equal(mymodule.fun('Сергей'), 'Привет, Сергей!');
});
});
});
Первый аргумент функции describe — это человекочитаемое описание поведения тестируемой функции или модуля, которое будет выводиться в консоль при прогоне тестов. Здесь желательно придерживаться некоторых структурных соглашений — например, в первом describe указывается имя модуля, во вложенном — имя тестируемой функции. Запустим mocha и убедимся, что тест нашей функции проходит:
> mocha
mymodule
#fun()
✓ должна приветствовать пользователя, имя которого передано как аргумент
1 passing (7ms)
Использование Mocha в IntelliJ IDEA
Mocha также умеет мониторить исходники и автоматически прогонять тесты при изменении кода. Запустить её в таком режиме можно и из командной строки с помощью параметра запуска --watch, но раз уж мы строим наш рабочий процесс в IntelliJ IDEA, то используем для этого специальную конфигурацию запуска:

В окне настройки конфигурации запуска укажем название этой конфигурации (Name), а также путь к папке с тестами (Test directory). Сохраним конфигурацию.

Изменим код функции так, чтобы он не проходил, и выполним (Run) конфигурацию запуска Mocha.

Теперь щёлкнем кнопку Toggle auto-test в появившейся панели. Эта кнопка включает режим автоматического прогона тестов при изменении исходников.

Исправим код функции, при этом Mocha автоматически прогонит тест и покажет, что теперь всё хорошо:

Ресурсы
- Документация по node.js — основной источник информации, хотя местами довольно лаконичный, и структурированный вокруг стандартных модулей.
- Веб-репозиторий npm — поиск библиотек, информация о них.
- Awesome List для node.js — незаменимый источник информации о проверенных библиотеках и решениях для разработки на node.js.
- Практики использования node.js в продакшне — информационный портал компании Joyent, занимающейся поддержкой node.js.