За последний десяток лет я разработал множество full-stack приложений. По роду своей деятельности постоянно пишу API для взаимодействия не только между фронтендом и бэкендом, но и другими сервисами. Как правило, для запроса и хранения данных применяется следующая технологическая последовательность:

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

К счастью, не я один интересовался данным вопросом, так что за последние несколько лет в мире разработки появились разные варианты решения этой задачи.
Один из них заключается в работе с метафреймворками (например Remix), которые объединяют фронтенд- и бэкенд-фреймворки, предоставляя отличные возможности для full-stack разработки:

Объединение и интеграция обеспечивают широкий набор функциональностей, а также ускоряют процесс разработки. Однако я сомневался, стоит ли задействовать подобные инструменты. Дело в том, что я еще не оправился от перехода с AngularJS на новый Angular, поэтому опасался связываться с каким-либо фреймворком, не говоря уже о метафреймворке. Меньше всего хотелось переписывать фронтенд, бэкенд и весь алгоритм взаимодействия просто из-за прекращения обслуживания фреймворка (версии). Моя задача — максимально быстро заменить устаревшее наполнение с минимальными последствиями.
В связи с этим я обратился к другому варианту решения в виде инструмента-посредника (англ. mediator), который “склеивает” оба конца с помощью связующего кода. Это концепция воплощается в Inertia:

Аналогично метафреймворку посредник берет на себя все взаимодействия с фреймворками. При этом сам он не является фреймворком, а просто обеспечивает связующий слой. Такие подходы, как Inertia, предоставляют адаптеры для часто используемых фронтенд- и бэкенд-фреймворков с возможностью выбора. Как по мне, этот вариант выглядит предпочтительнее. Однако по-прежнему существует сильная зависимость от посредника и адаптеров. С каждым новым релизом посредника или фреймворка в случае внесения критических изменений адаптеры должны обновляться. Пока налажено обслуживание, это осуществимо, но что будет через 4 или 5 лет?
Проанализировав оба решения, я понял, что гоняюсь за призраками. Единственный вариант избежать дополнительных зависимостей — связать оба конца вместе без каких-либо промежуточных элементов. Однако подобного решения я не нашел и оставил все как есть, снова и снова возвращаясь к этому вопросу. И тут меня осенило: с этой задачей справится среда выполнения.

Именно эта идея простимулировала разработку Jitar, распределенной среды выполнения для приложений JavaScript и TypeScript. Это решение опирается на конфигурацию и не присутствует в самом коде. Функции сервера можно импортировать и вызывать напрямую на клиенте:
import { someFunction } from './server';
const answer = await someFunction();
Благодаря такому подходу код становится чистым, простым и акцентированным, поскольку обходится без каких-либо посредников. Клиент не знает, какая функция выполняется на другом конце, да ему это и не нужно. Определением того, что и где выполняется, занимается конфигурация. При этом не важно, какие применяются фреймворки.
Использование JavaScript/TypeScript на обоих концах ограничивает выбор фреймворков, но зато позволяет запускать одни и те же компоненты как на клиенте, так и на сервере. Кроме того, значительно улучшается процесс разработки, поскольку по всему приложению доступны проверка типов и технология автодополнения Intellisense. В данном пункте другие решения все еще испытывают проблемы .
Заменить Jitar очень легко — достаточно просто перестать использовать среду выполнения и выбрать другой механизм взаимодействия. Скорее всего, подразумевается создание API, без которого мы пока обходились.
В Jitar я нашел долгожданное решение. Это проект с открытым ПО, выпускаемый под лицензией MIT. В настоящее время все больше и больше разработчиков участвуют в его доработке и совершенствовании. Вы тоже можете внести свой вклад. Более подробная информация о Jitar содержится в документации и репозитории GitHub.
Читайте также:
- Что такое Throttling и Debouncing?
- Lego-build: новое решение старой проблемы
- Service Workers и стратегии кэширования
Читайте нас в Telegram, VK и Дзен
Перевод статьи Peter van Vliet: How I Speed Up Full-stack Development by Not Building APIs