https://habr.com/ru/post/510090/- Разработка веб-сайтов
- JavaScript
- Программирование
- Node.JS
Доброго времени суток, друзья!
Продолжаю публиковать перевод этого
руководства по Node.js.
Другие части:
Часть 1
Часть 2
Часть 3
Получение данных, введенных пользователем, в Node.js
Как сделать Node.js-программу интерактивной?
Для этого в 7 версии Node.js представлен модуль
readline: он служит для получения данных из потока для чтения, такого как
process.stdin
— командная строка во время выполнения Node.js-программы.
const readline = require('readline').createInterface({
input: process.stdin,
output: process.stdout
})
readline.question(`What is your name?`, name => {
console.log(`Hi ${name}!`)
readline.close()
})
В этом коде запрашивается имя пользователя, после того, как пользователь набрал текст и нажал
enter
, выводится приветствие.
Метод
question()
выводит в консоль первый параметр (вопрос) и ожидает ответа пользователя. При нажатии
enter
выполняется функция обратного вызова.
В данном коллбэке мы закрываем интерфейс
readline
.
readline
содержит и другие методы, о которых вы можете почитать в документации.
Если вам необходимо запросить пароль, лучше не возвращать его в явном виде, а использовать символы
*
.
Одним из способом это сделать является использование пакета
readline-sync, который прост для понимания и легок в настройке.
Более полное и абстрактное решение предоставляет пакет
Inquirer.js.
Устанавливаем его с помощью
npm install inquirer
и используем следующим образом:
const inquirer = require('inquirer')
const questions = [
{
type: 'input',
name: 'name',
message: `What's your name?`
}
]
inquirer.prompt(questions).then(answers => {
console.log(`Hi ${answers['name']}!`)
})
Inquirer.js позволяет делать много интересных вещей, например, предлагать множественный выбор, предоставлять радио-кнопки, запрашивать подтверждение действия и т.д.
Он больше известен как альтернатива встроенным решениям, но если вы планируете поднять взаимодействие с пользователем на новый уровень, Inquirer.js — оптимальное решение.
Расширение функциональности Node.js-файла с помощью экспорта
Node.js имеет встроенную модульную систему.
Node.js-файл может импортировать функциональность из других Node.js-файлов.
Когда вы хотите что-либо импортировать вы используете
const library = require('./library')
для импорта функциональности, экспортируемой в файле
library.js
, находящейся в текущей директории.
В этом файле функционал должен быть экспортирован перед тем, как его можно будет импортировать в другом файле.
Любой другой объект или переменная, определенные в файле, по умолчанию являются приватными (частными) и не могут быть использованы в других файлах.
Вот что нам позволяет делать интерфейс
module.exports
, предоставляемый
модульной системой.
Когда вы присваиваете объект или функцию в качестве нового свойства объекта
exports
, вы их экспортируете, и после этого они могут быть импортированы в другом месте приложения или в другом приложении.
Это можно сделать двумя способами.
Первый способ заключается в присваивании значения
module.exports
, который является объектом, предоставляемым модульной системой по умолчанию. Этот способ позволяет экспортировать только данный объект:
const car = {
brand: 'Ford',
model: 'Fiesta'
}
module.exports = car
// в другом файле
const car = require('./car')
Вторым способом является добавление экспортируемого объекта в качестве свойства объекта
exports
. Этот способ позволяет экспортировать множество объектов, функций или данных:
const car = {
brand: 'Ford',
model: 'Fiesta'
}
exports.car = car
или так
exports.car = {
brand: 'Ford',
model: 'Fiesta'
}
Для использования данного объекта в другом файле необходимо сделать ссылку на импорт:
const items = require('./items')
items.car
или
const car = require('./items').car
В чем разница между
module.exports
и
exports
?
Первый экспортирует объект, на который ссылается, второй — свойство объекта.
Введение в пакетный менеджер npm
Введение в npm
npm
— это стандатный пакетный менеджер Node.js.
В январе 2017 года в npm числилось свыше 350000 пакетов, что сделало его самым большим репозиторием кода на одном языке программирования на Земле, и можете быть уверенными в том, что существуют пакеты для решения практически любых задач.
Все начиналось с загрузки и управления зависимостями в Node.js, но вскоре данный инструмент стал активно использоваться при разработке клиентской части приложений.
npm
делает несколько вещей.
Альтернативой npm является
yarn.
Загрузка
npm
управляет загрузкой зависимостей проекта.
Если в проекте существует файл
package.json
посредством запуска
npm install
будет установлено все, что требуется проекту, в каталог
node_modules
, который создается при отсутствии.
Определенный пакет можно установить с помощью
npm install <package-name>
.
Часто установка пакета сопровождается флагами:
- --save — установка пакета и добавление записи о нем в раздел dependencies файла
package.json
- --save-dev — установка пакета и добавление записи о нем в раздел devDependencies файла
package.json
Разница в основном состоит в том, что devDependencies используется в целях разработки, например, для тестирования, а dependencies — в продакшне (при сборке проекта).
Обновление пакетов
Обновление легко выполняется с помощью
npm update
.
npm
проверит все пакеты на наличие новых версий, удовлетворяющих установленным ограничениям.
Вы также можете обновить лишь определенный пакет:
npm update <package-name>
.
Версионирование
В дополнение к стандартной загрузке, npm поддерживает версионирование, поэтому вы можете определить любую конкретную версию пакета, или запросить более новую или старую версии.
Вы часто будете сталкиваться с тем, что одна библиотека совместима только с определенной (мажорной) версией другой библиотеки.
А также с багами последних релизов, которые не устраняются долгое время.
Определение версий также способствует командной разработке, поскольку каждый член команды знает, какую версию использовать до обновления файла
package.json
.
Во всех этих случаях помогает версионирование, в этом плане
npm
следует принятым стандартам.
Выполнение задач
package.json
поддерживает формат для определения команд, выполняемых в терминале, с помощью
npm run <task-name>
.
Например:
{
"scripts": {
"start-dev": "node lib/server-development",
"start": "node lib/server-production"
},
}
Распространенной практикой является использование этой возможности для запуска Webpack:
{
"scripts": {
"watch": "webpack --watch --progress --colors --config webpack.conf.js",
"dev": "webpack --progress --colors --config webpack.conf.js",
"prod": "NODE_ENV=production webpack -p --config webpack.conf.js"
},
}
Это позволяет вместо набора длинных команд, которые легко забыть или при наборе которых легко ошибиться, делать так:
npm run watch
npm run dev
npm run prod
Куда npm устанавливает пакеты?
При установке пакетов с помощью
npm
вы можете выбрать два типа установки:
По умолчанию, когда вы вводите
npm install
, например:
npm install lodash
пакет устанавливается в папку
node_modules
в текущей директории.
После установки
npm
добавляет запись о
lodash
в раздел
dependencies
файла
package.json
в текущей директории.
Для глобальной установки следует использовать флаг
-g
:
npm install -g lodash
При глобальной установке пакет устанавливается не в текущую директорию, а в глобальную.
Но куда именно?
Для определения этого необходимо выполнить команду
npm root -g
.
На macOS или Linux такой директорией может быть
/usr/local/lib/node_modules
. На Windows —
C:\Users\YOU\AppData\Roaming\npm\node_modules
.
При использовании
nvm
для управления версиями Node.js эта директория может отличаться.
Как использовать установленные пакеты?
Как использовать установленный в папку
node_modules
или глобально пакет.
Скажем, вы установили
lodash
, популярную вспомогательную JavaScript-библиотеку, с помощью
npm install lodash
.
Эта команда установит
lodash
в локальную директорию
node_modules
.
Для использования в программе необходимо импортировать пакет с помощью
require
:
const _ = require('lodash')
Что если пакет является исполняемым (файлом)?
В этом случае, исполняемый файл будет помещен в каталог
node_modules/.bin/
.
Это легко продемонстрировать с помощью библиотеки
cowsay.
Данный пакет предоставляет программу для командной строки, при выполнении которой корова (и другие животные) что-либо «произносит».
При установке пакета посредством
npm install cowsay
, будет установлен сам пакет и несколько его зависимостей:
Папка
.bin
является скрытой и содержит символические ссылки на бинарные данные cowsay:
Как их выполнить?
Вы, конечно, можете набрать
./node_modules/.bin/cowsay
и все будет работать, но npx, включенный в npm (начиная с версии 5.2), является лучшим вариантом. Вы просто выполняете
npx cowsay
и npx определит местонахождения файла автоматически:

Корова говорит: «забери меня отсюда».
Руководство по package.json
При работе с JavaScript, при взаимодействии с JavaScript-проектом, Node.js или клиентской частью приложения, вы наверняка встретите файл
package.json
.
Что это такое? Что вы должны о не знать? И что вы можете с ним делать?
package.json
— это своего рода манифест проекта. Он может делать много вещей, совершенно не связанных между собой. Он, например, может являться главным файлом для настроек используемых инструментов. В нем также хранятся названия и версии всех установленных пакетов (эта информация используется
npm
и
yarn
).
Структура файла
Вот пример
package.json
:
{}
Как видите, он пустой. К содержанию
package.json
не предъявляется никаких требований. Единственным требованием является его формат (JSON), в противном случае, программы не смогут получить к нему доступ.
Если вы создаете Node.js-пакет, который планируете распространять через
npm
, ситуация кардинально меняется, и вам необходимо добавить свойства, которые помогут другим людям использовать пакет. Мы рассмотрим это позже.
Вот еще один пример
package.json
:
"name": "test-project"
Здесь мы определили название пакета или приложения, находящего в той же директории, что и
package.json
.
Вот пример более сложного
package.json
, позаимствованного из Vue.js-приложения:
{
"name": "test-project",
"version": "1.0.0",
"description": "A Vue.js project",
"main": "src/main.js",
"private": true,
"scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"start": "npm run dev",
"unit": "jest --config test/unit/jest.conf.js --coverage",
"test": "npm run unit",
"lint": "eslint --ext .js,.vue src test/unit",
"build": "node build/build.js"
},
"dependencies": {
"vue": "^2.5.2"
},
"devDependencies": {
"autoprefixer": "^7.1.2",
"babel-core": "^6.22.1",
"babel-eslint": "^8.2.1",
"babel-helper-vue-jsx-merge-props": "^2.0.3",
"babel-jest": "^21.0.2",
"babel-loader": "^7.1.1",
"babel-plugin-dynamic-import-node": "^1.2.0",
"babel-plugin-syntax-jsx": "^6.18.0",
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.0",
"babel-plugin-transform-runtime": "^6.22.0",
"babel-plugin-transform-vue-jsx": "^3.5.0",
"babel-preset-env": "^1.3.2",
"babel-preset-stage-2": "^6.22.0",
"chalk": "^2.0.1",
"copy-webpack-plugin": "^4.0.1",
"css-loader": "^0.28.0",
"eslint": "^4.15.0",
"eslint-config-airbnb-base": "^11.3.0",
"eslint-friendly-formatter": "^3.0.0",
"eslint-import-resolver-webpack": "^0.8.3",
"eslint-loader": "^1.7.1",
"eslint-plugin-import": "^2.7.0",
"eslint-plugin-vue": "^4.0.0",
"extract-text-webpack-plugin": "^3.0.0",
"file-loader": "^1.1.4",
"friendly-errors-webpack-plugin": "^1.6.1",
"html-webpack-plugin": "^2.30.1",
"jest": "^22.0.4",
"jest-serializer-vue": "^0.3.0",
"node-notifier": "^5.1.2",
"optimize-css-assets-webpack-plugin": "^3.2.0",
"ora": "^1.2.0",
"portfinder": "^1.0.13",
"postcss-import": "^11.0.0",
"postcss-loader": "^2.0.8",
"postcss-url": "^7.2.1",
"rimraf": "^2.6.0",
"semver": "^5.3.0",
"shelljs": "^0.7.6",
"uglifyjs-webpack-plugin": "^1.1.1",
"url-loader": "^0.5.8",
"vue-jest": "^1.0.2",
"vue-loader": "^13.3.0",
"vue-style-loader": "^3.0.1",
"vue-template-compiler": "^2.5.2",
"webpack": "^3.6.0",
"webpack-bundle-analyzer": "^2.9.0",
"webpack-dev-server": "^2.9.1",
"webpack-merge": "^4.1.0"
},
"engines": {
"node": ">= 6.0.0",
"npm": ">= 3.0.0"
},
"browserslist": ["> 1%", "last 2 versions", "not ie <= 8"]
}
Здесь много всего:
name
— название приложения/пакета
version
— версия приложения/пакета
description
— краткое описание приложения/пакета
main
— главный файл (точка входа) приложения
private
— значение true
предотвращает случайную публикация приложения в npm
scripts
— набор скриптов (команд), которые можно запускать (выполнять)
dependencies
— зависимости проекта
devDependencies
— зависимости проекта, используемые только при разработке
engines
— версии, на которых работает приложение/пакет
browserlist
— поддерживаемые браузеры (и их версии)
Все эти свойства используются
npm
.
Свойства
В этом разделе мы поговорим о некоторых свойствах, которые вы можете использовать. Мы будем использовать термин «пакет», однако большая часть из сказанного также справедлива по отношению к приложениям.
Большинство свойств нужны для публикации пакета в
npm
, некоторые для взаимодействия с пакетом.
Название (имя)
Определяет название пакета.
Например:
"name": "test-project"
Имя не должно превышать 214 символов, не должно содержать пробелов, может состоять только из строчных букв (нижний регистр), дефисов (-) и нижнего подчеркивания (_).
Это обусловлено тем, что при публикации в
npm
пакету присваивается URL на основе его имени.
Если пакет опубликован на GitHub, хорошей практикой считается указание ссылки на репозиторий.
Автор
Определяет автора пакета.
Например:
{
"author": "Joe <joe@whatever.com> (https://whatever.com)"
}
или так:
{
"author": {
"name": "Joe",
"email": "joe@whatever.com",
"url": "https://whatever.com"
}
}
Соавторы
Определяет одного или более соавторов пакета. Данное свойство представляет собой массив из строк.
Например:
{
"contributors": ["Joe <joe@whatever.com> (https://whatever.com)"]
}
или так:
{
"contributors": [
{
"name": "Joe",
"email": "joe@whatever.com",
"url": "https://whatever.com"
}
]
}
Ошибки
Определяет ссылку на инструкцию по решению проблем, обычно, на трекер ошибок (issue tracker) GitHub.
Например:
{
"bugs": "https://github.com/whatever/package/issues"
}
Домашняя страница
Определяет адрес домашней страницы.
Например:
{
"homepage": "https://whatever.com/package"
}
Версия
Определяет текущую версию пакета.
Например:
"version": "1.0.0"
Данное свойство следует стандарту семантического версионирования. Это означает, что оно всегда должно состоять из трех чисел, разделенных точками:
x.x.x
.
Первая цифра — мажорная версия, вторая — минорная, третья — патч.
Каждая цифра имеет определенный смысл: обновление с целью устранения ошибок — это патч, релиз обратно совместимых изменений — это минорный релиз, мажорный релиз может означать несовместимые с предыдущей версией изменения.
Лицензия
Определяет лицензию пакета.
Например:
"license": "MIT"
Ключевые слова
Данное свойство представляет собой массив ключевых слов, ассоциируемых с пакетом.
Например:
"keywords": [
"email",
"machine learning",
"ai"
]
Они помогают людям в поиске пакетов.
Описание
Определяет краткое описание пакета.
Например:
"description": "A package to work with strings"
При публикации пакета в
npm
данное свойство помогает людям понять, для чего он нужен.
Репозиторий
Определяет, где находится исходный код пакета.
Например:
"repository": "github:whatever/testing",
Обратите внимание на префикс
github
. Существует и другие подобные сервисы:
"repository": "gitlab:whatever/testing",
"repository": "bitbucket:whatever/testing",
Вы также можете определить систему контроля версий:
"repository": {
"type": "git",
"url": "https://github.com/whatever/testing.git"
}
Вы можете указать несколько систем контроля версий:
"repository": {
"type": "svn",
"url": "..."
}
main
Определет главный файл (точку входа) пакета.
При импорте пакета в приложение, именно в этом файле приложение будет искать экспортируемые модули.
Например:
"main": "src/main.js"
private
Установка данному свойству значения
true
предотвращает пакет от случайной публикации в
npm
.
Например:
"private": true
scripts
Определяет список команд (скриптов), которые можно выполнять (запускать).
Например:
"scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"start": "npm run dev",
"unit": "jest --config test/unit/jest.conf.js --coverage",
"test": "npm run unit",
"lint": "eslint --ext .js,.vue src test/unit",
"build": "node build/build.js"
}
Эти скрипты являются приложениями командной строки. Вы можете запускать их с помощью
npm run XXXX
или
yarn run XXXX
, где
XXXX
— это название команды. Например:
npm run dev
.
В качестве названия команды можно использовать любое имя, скрипт выполнит все, что вы в нем укажете.
Зависимости (dependencies)
Определяет список зависимостей пакета.
При установке пакета с помощью npm или yarn:
npm install <PACKAGENAME>
yarn add <PACKAGENAME>
запись об этом пакете будет автоматически добавлена в рассматриваемое свойство.
Например:
"dependencies": {
"vue": "^2.5.2"
}
devDependencies
Определяет список зависимостей для целей разработки.
Они отличаются от
dependencies
, поскольку устанавливаются только на компьютере разработчика, и не попадают в продакшн.
При установке пакета с помощью npm или yarn:
npm install --save-dev <PACKAGENAME>
yarn add --save-dev <PACKAGENAME>
запись о нем авоматически добавляется в рассматриваемое свойство.
Например:
"devDependencies": {
"autoprefixer": "^7.1.2",
"babel-core": "^6.22.1"
}
engines
Определяет, на каких версиях Node.js или других инструментов работает пакет/приложение.
Например:
"engines": {
"node": ">= 6.0.0",
"npm": ">= 3.0.0",
"yarn": "^0.13.0"
}
browserlist
Определяет список поддерживаемых браузеров (и их версий). Эта информация используется Babel, Autoprefixer и другими инструментами для создания полифилов и обеспечения совместимости с указанными браузерами.
Например:
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
Данная настройка означает, что вы хотите поддерживать две последние версии всех браузеров, которыми пользуется более 1% людей по статистике
CanIUse, за исключением IE8 и более старых версий.
Специальные свойства
package.json
может содержать специальные свойства для таких инструментов, как Babel, ESLint и т.п.
Каждый из этих инструментов имеет собственные свойства, например,
eslintConfig
,
babel
и проч. Подробности о специальных свойствах смотрите в соответствующей документации.
Версии пакета
В приведенных выше примерах вы наверняка заметили записи вроде этих:
~3.0.0
,
^0.13.0
. Что они означают? И какие еще спецификаторы версий можно использовать?
Данные спецификаторы используются для определения условий обновления.
Правила следующие:
~
— запись ~0.13.0
означает, что допустимы лишь патчевые обновления, т.е. релиз 0.13.1
допустим, а релиз 0.14.0
нет
^
— запись ^0.13.0
означает, что допустимы патчевые и минорные обновления
*
— запись *
означает, что допустимы любые обновления
>
— допустимы любые новые версии
>=
— допустимы аналогичные или более новые версии
<=
— допустимы аналогичные или более старые версии
<
— допустимы любые старые версии
Вот еще парочка правил:
- без символа в начале — допустима только указанная версия
latest
— допустима только последняя версия
Указанные символы можно комбинировать различными способами, например:
1.0.0 || >=1.1.0 <1.2.0
.
Благодарю за внимание.
Продолжение следует…