Зарегистрируйтесь, чтобы продолжить обучение

Точка входа JS: Настройка окружения

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

Точка входа для приложения

Большинство приложений — это достаточно объемный проект, состоящий из множества модулей. Но когда запускается приложение, то запускается какой-то один конкретный файл, он и является точкой входа:

// file: src/my-application/index.js

export default () => console.log('Welcome to my application!')

// file: index.js
import app from './src/my-application/index.js'

app()

Выше пример небольшого проекта из двух файлов:

  • src/my-application/index.js — определена и экспортирована функция, выводящая сообщение в консоль
  • index.js — импортируется и вызывается функция
.
├── index.js
├── package.json
└── src
    └── my-application
        └── index.js

Модуль index.js в таком проекте является точкой входа. Если вызвать этот файл командой node index.js из директории проекта, то начнется выполнение нашего приложения, произойдет вызов функции app(), и мы увидим результат:

node index.js
Welcome to my application!

В проекте бывают несколько точек входа. Каждая может работать как отдельное приложение и при этом использовать общую логику.

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

Точка входа для библиотеки

Если в приложениях точкой входа является то место, где происходит вызов самого приложения в виде функции или какого-то кода, то для библиотек ситуация иная. В библиотеках мы не должны в обычной ситуации вызывать код. Библиотека предоставляет функцию или набор функций, а когда их вызывать решает тот, кто импортирует библиотеку в свой модуль.

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

import { random } from 'lodash'

console.log(random(0, 5))

Когда мы указываем подобный импорт, мы не указываем конкретный файл, откуда нужно импортировать функцию, а только указываем название библиотеки. Но как тогда интерпретатор узнает где находится нужная нам функция? Это происходит благодаря тому, что в npm-пакете есть точка входа для этого самого пакета, то есть точка входа библиотеки, npm-пакет является библиотекой.

Чтобы указать точку входа библиотеки, которую мы разрабатываем, мы должны указать в package.json в свойстве "main" путь к файлу, который экспортирует нашу функцию или набор функций, если библиотека предоставляет несколько функций. Благодаря этому, тем, кто будет использовать эту библиотеку, не нужно знать в каком файле определена функция. Модуль, который указан в "main" и будет импортироваться при импорте всей библиотеки.

Точка входа библиотеки и приложения в одном проекте

Часто бывает такое, что проект является приложением, но при этом его так же можно сделать и библиотекой. Представьте, что вы разрабатываете небольшое приложение, которое спрашивает у пользователя его возраст и печатает на экран в каком году он родился.

Решая эту задачу в лоб, вы можете написать в своем проекте один единственный файл. Не будем вдаваться в подробности кода, сейчас это не так важно:

// file: index.js
console.log('Сколько вам лет?')
const age = 18 // Каким-то способом получаем возраст пользователя, через терминал. Сейчас не важно как
const birthYear = 2005 // Подсчитываем результат
console.log(`Ваш год рождения: ${birthYear}`)

Вы можете пока не знать как получить значение, которое пользователь ввел в терминал или как получить текущую дату, чтобы рассчитать нужный год. Сейчас это не важно, поэтому в коде мы просто поставили заготовленные ответы.

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

// file: src/index.js
export default (age) => {
  const birthYear = 2005 // Подсчитываем результат

  return birthYear
}

// file: index.js
import getBirthYear from './src/index.js'

console.log('Сколько вам лет?')
const age = 18 // Каким-то способом получаем возраст пользователя, через терминал. Сейчас не важно как
const birthYear = getBirthYear(age)
console.log(`Ваш год рождения: ${birthYear}`)

Мы выделили функцию подсчета года рождения в отдельный модуль. Теперь мы можем указать в "main" нашего пакета путь к этому модулю ./src/index.js. Теперь все, кто будет импортировать наш пакет, смогут использовать функцию для подсчета года рождения. Выделив функцию, мы значительно повысили возможности переиспользования нашего проекта.

Хорошей практикой считается всегда выделять подобные функции в ваших проектах. Это делается не только для переиспользования. Например, это значительно упрощает тестирование вашего проекта.

Обратите внимание, что мы не добавили вызов console.log() и получение возраста в функцию. Это сделано потому, что эти операции предназначены только для консольных приложений. Если бы мы вместо возврата значения из функции делали просто вывод в консоль, то такую функцию нельзя было бы использовать для других задач, например, для веб-приложений.

По умолчанию в "main" указывается файл index.js — это файл, который находится в корне проекта. Ниже пример package.json как он мог бы выглядеть для нашего проекта:

{
  "name": "birth-year",
  "type": "module",
  "version": "1.0.0",
  "description": "",
  "main": "src/index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

Свойство "main" указывает на файл src/index.js.

.
├── index.js
├── package.json
└── src
    └── index.js

Итог

Мы познакомились с точками входа для приложений и библиотек. Разобрали, что для приложений точка входа является местом, где начинается выполнение кода, а для библиотек это модуль с экспортом сущностей и указанный в "main". Так же мы разобрали как можно расширить возможности проекта с помощью выделения логики в отдельную функцию, которая может быть переиспользована в других задачах. Все, что мы обсудили, тесно связано с проектированием проекта и позволит заложить фундамент хорошей архитектуры для сложных проектов.


Самостоятельная работа

  1. В проекте hexlet-js изучите какой файл импортируется из библиотеки lodash при импорте функций из этой библиотеки
  2. Перенесите логику из index.js в src/index.js, оберните в функцию и экспортируйте ее
  3. В файле index.js сделайте импорт функции из src/index.js и вызов этой функции
  4. Укажите в "main" путь к модулю с экспортом функции
  5. Добавьте все изменения на гитхаб

Дополнительные материалы

  1. Совершенный код: проектирование функций

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff