Главная » Хабрахабр » [Перевод] Когда исчезнут JavaScript-фреймворки?

[Перевод] Когда исчезнут JavaScript-фреймворки?

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

Что такое «фреймворк»?

Если попытаться дать определение JavaScript-фреймворка, не вдаваясь в детали, то окажется, что это — инструмент, который можно использовать для разработки сложных веб-приложений, в частности — одностраничных приложений (Single Page Application, SPA).

Но, с ростом сложности фронтенд-приложений, начали появляться и соответствующие инструменты, облегчающие жизнь программистов. В былые времена такие приложения создавали, полагаясь на возможности чистого JavaScript и библиотеки jQuery. Например — это React, Angular и Vue.

Так, большинство фронтенд-фреймворков и библиотек, условно говоря, от Vue до React, дают в распоряжение разработчика некую комбинацию следующих возможностей: Фреймворки, которые популярны в наши дни, обладают некоторыми схожими общими чертами.

  • Синхронизация состояния и визуального представления приложения.
  • Маршрутизация.
  • Система шаблонов.
  • Компоненты, подходящие для повторного использования.

Необходимы ли фреймворки современному разработчику?

Ответ на вопрос, вынесенный в заголовок этого раздела, зависит от того, как относиться к идее «необходимости» фреймворков. Уверен, многие могут сказать о том, что фронтенд-фреймворки не являются необходимыми в наборе инструментов веб-разработчика, и никогда необходимыми не были. Хотя бесспорно то, что это — весьма полезные инструменты.

Можно ли решать задачи, на решение которых они направлены, другими средствами, например такими, которые появились в распоряжении программистов в ходе развития браузерных API»? Собственно говоря, наш вопрос можно переформулировать так: «Являются ли фреймворки чем-то вроде «современной библиотеки jQuery»?

jQuery

На самом деле, на этот вопрос ответить непросто, но можно сказать, что развитие JavaScript, технологий работы с веб-компонентами и инструментов для сборки проектов сделало разработку SPA без использования фреймворков простой как никогда.

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

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

Обзор экспериментального приложения

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

Домашняя страница приложения

Страница создания записи о рецепте

Веб-компоненты

Создание веб-компонентов — занятие несложное. В частности, речь идёт о создании класса, расширяющего HTMLElement (или HTMLParagraphElement, и так далее) и о последующем использовании этого класса для описания собственного элемента.

Кроме того, при работе с веб-компонентами можно использовать хуки их жизненного цикла, такие, как connectedCallback, disconnectedCallback, attributeChangedCallback.

Вот код компонента recipe-item, который предназначен для вывода рецептов в списке.

import template from './recipe.html'
import DATA_SERVICE from '../../utils/data'
export default class Recipe extends HTMLElement ) this._recipe = null this.ds = new DATA_SERVICE() } connectedCallback () { // устанавливаем в качестве html-содержимого импортированный шаблон this._shadowRoot.innerHTML = template // прикрепляем метод delete к соответствующей кнопке this._shadowRoot .querySelector('.delete') .addEventListener('click', () => this._delete()) } _render (title) { // задаём заголовок рецепта и текст кнопки, позволяющей отметить рецепт this._shadowRoot.querySelector('.recipe-title').innerHTML = title this._shadowRoot.querySelector('.favorite').innerHTML = this._recipe .favorite ? 'Unfavorite' : 'Favorite' } _delete () { // удаление рецепта или вывод сообщения об ошибке try { await this.ds.deleteRecipe(this._recipe.id) } catch (e) { console.error(e) alert( 'Sorry, there was a problem deleting the recipe. Please, try again.' ) } } get recipe () { // геттер для рецепта return this._recipe } set recipe (recipe = {}) { // сеттер для рецепта, вызывающий метод render this._recipe = recipe this._render(this._recipe.title) }
} window.customElements.define('recipe-item', Recipe)

Маршрутизация

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

Но, с использованием API History, совсем несложно реализовать собственный маршрутизатор, на который придётся что-то около 100 строк кода. Изначально я, для организации навигации в приложении, использовал npm-пакет Vanilla JS Router. Обратите внимание на то, что в этом примере не реализовано что-то действительно сложное, наподобие средств ограничения доступа к определённым маршрутам (route guard).

import './components/error/error'
import content404 from './components/404/404.html'
import DATA_SERVICE from './utils/data'
const ds = new DATA_SERVICE()
// получаем элемент, содержащий SPA
const $el = document.getElementById('app') // объявляем маршруты
const home = async () => { await import('./components/recipe/recipe') await import('./components/recipe-list/recipe-list') await import('./components/modal/modal.js') $el.innerHTML = `<recipe-list></recipe-list>`
} const create = async () => { await import('./components/create-recipe/create-recipe') $el.innerHTML = `<create-recipe></create-recipe>`
} const edit = async () => { await import('./components/edit-recipe/edit-recipe') $el.innerHTML = `<edit-recipe></edit-recipe>`
} const error404 = async () => { $el.innerHTML = content404
} // установление соответствия маршрутов и путей
// получение рецепта по id для создания маршрута редактирования рецепта
const routes = { '/': home, '/create': create, '/error': error404, '/edit': async function (params) { const id = params.get('id') const recipe = await ds.getRecipe(id) await edit() $el.querySelector('edit-recipe').recipe = recipe }
} // по событию onpopstate получить параметры из URL и передать их маршруту
// если нужного маршрута найти не удаётся - использовать маршрут /error
window.onpopstate = async () => { const url = new URL( window.location.pathname + window.location.search, window.location.origin ) if (routes[window.location.pathname]) { await routes[window.location.pathname](url.searchParams) } else routes['/error']()
}
// добавление маршрута в историю браузера
let onNavItemClick = async pathName => { const url = new URL(pathName, window.location.origin) const params = url.searchParams if (routes[url.pathname]) { window.history.pushState({}, pathName, window.location.origin + pathName) await routes[url.pathname](params) } else { window.history.pushState({}, '404', window.location.origin + '/404') routes['/error']() }
} // установка подходящего маршрута при загрузке и перезагрузке страницы
;(async () => { const url = new URL( window.location.pathname + window.location.search, window.location.origin ) if (routes[window.location.pathname]) { await routes[window.location.pathname](url.searchParams) } else routes['/error']()
})() // экспорт маршрутов и метода onNavItemClick()
const router = { onNavItemClick, routes
}
export { router }

Здесь приведён краткий обзор основных строительных блоков приложения, так как его полное описание нам тут не требуется. На самом деле, в нём реализованы, помимо описанных возможностей, и другие — вроде бесконечного скроллинга и интерфейса для загрузки картинок на сайт путём их перетаскивания в соответствующее место страницы.

Сравнение разработки с использованием JS и фреймворков

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

Минусы отказа от фреймворков

▍Проблемы стандартизации

Спецификации веб-компонентов, с одной стороны, существуют уже довольно давно, а с другой, всё ещё развиваются. Так, веб-компоненты были представлены Алексом Расселом на мероприятии Fronteers Conference 2011. Однако серьёзная работа в направлении их поддержки и развития ведётся только в последние год или два. В результате в спецификациях всё ещё царит беспорядок. Например, технология HTML-импортов уже неактуальна, хотя о ней пишут в документации и в различных публикациях.

▍Тестирование

Имеется не особенно много решений для тестирования стандартных веб-компонентов. Так, существуют некоторые многообещающие инструменты — вроде skatejs ssr или web-component-tester. Но эти инструменты предназначены для применения с соответствующими библиотеками. В результате у того, кто хочет пользоваться веб-компонентами, возникают определённые сложности.

▍Синхронизация интерфейса и состояния приложения

Конструкции querySelector()

Именно такие системы и привлекают многих к Angular и к другим фреймворкам. При разработке веб-приложений очень важно, чтобы в распоряжении программиста была бы некая базовая система, автоматически синхронизирующая данные и их представление на странице.

Но в ходе роста проекта синхронизация способна быстро превратиться в проблему, разработчику, для поддержки приложения в работоспособном состоянии, придётся добавлять в него множество прослушивателей событий и команд выбора элементов. Если речь идёт о небольших проектах, то синхронизация состояния приложения с его визуальным представлением — задача не особенно сложная.

▍Технология Shadow DOM

Я всё ещё сомневаюсь в технологии Shadow DOM. С одной стороны мне нравится идея инкапсуляции. Это — адекватный паттерн проектирования, упрощающий управление стилями и облегчающий работу программиста. Но, с другой стороны, его использование сопряжено со сложностями, в том случае, если нужно, чтобы что-то выходило бы за границы инкапсулированных сущностей. Например, это касается применения общих стилей. Вопрос о том, как их использовать правильно, всё ещё открыт.

▍Работа с DOM

Фреймворки и библиотеки вроде Angular и React отчасти обязаны своей притягательностью тем, что они значительно упрощают работу с DOM. А именно, они отлично показывают себя при выводе и обновлении элементов. Вот что говорится об этом в блоге Angular University: «Angular напрямую генерирует структуры данных DOM, а не работает, создавая HTML-код и потом передавая его браузеру для последующей обработки».

Делается это вместо того, чтобы передавать браузеру HTML-код, который, перед попаданием в DOM, должен быть разобран. Angular, например, в отличие от jQuery, напрямую генерирует структуры данных DOM. Технология Virtual DOM также весьма полезна, так как она позволяет отказаться от повторного рендеринга всего содержимого страницы, выполняемого каждый раз при обновлении неких элементов. Такой подход отличается более высокой производительностью, так как благодаря его использованию устраняется шаг разбора HTML-кода.

Теперь поговорим о плюсах. Минусы отказа от фреймворков в пользу обычного JS мы рассмотрели.

Плюсы отказа от фреймворков

▍Размеры пакетов приложений

Пакет готового веб-приложения, разработанного на чистом JS, может оказаться (обратите внимание на слово «может») гораздо меньше, чем пакет аналогичного приложения, созданного с применением фреймворков. Например, пакет нашего готового экспериментального приложения, реализующего множество возможностей, в три раза меньше чем пакет пустого Angular-приложения.

Пакет пустого Angular-приложения

Пакет приложения, разработанного без использования фреймворков

▍Использование фреймворков и понимание технологий

Если вы разрабатывали веб-приложения исключительно с использованием неких фреймворков и их CLI, для того, чтобы создать приложение без вспомогательных инструментов, вам придётся очень постараться. Создание проектов без фреймворков позволяет изучить базовые технологии, инструменты и паттерны проектирования, которые лежат в основе современной веб-разработки. Эти знания, в любом случае, будете ли вы, приобретя их, пользоваться фреймворками, или не будете, окажутся полезными.

▍Производительность

То, что делается в недрах фреймворков и библиотек, позволяет получать замечательные результаты. Но за всё надо платить. В данном случае цена удобства — производительность. При этом, с ростом размера приложения, основанного на некоем фреймворке, может расти и нагрузка на систему, создаваемая вспомогательными механизмами, отвечающими за работу такого приложения. Систему нагружают ненужные операции по обновлению страниц, избыточные прослушиватели событий, глубокое сравнение объектов, без которого можно обойтись, неоправданно масштабные манипуляции с DOM. Избавиться от всего этого можно просто сделав всё своими силами.

Поэтому они уделяют немалое внимание оптимизации своих проектов. Тут хочется отметить, что команды разработчиков React и Angular, очевидно, знают о подобных проблемах. Например, речь идёт о чём-то вроде использования в React метода shouldUpdate() или о стратегии обнаружения изменений onPush в Angular.

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

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

Некоторые заметки и интересные наблюдения

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

Поэтому я называл их все «фреймворками». Ранее я был склонен считать React, Vue и Angular средствами для решения одних и тех же задач. Однако теперь мне ясно, почему React правильнее называть «библиотекой», а Vue — «прогрессивным фреймворком».

Дело в том, что я, при работе над рассматриваемым здесь проектом, стремился к тому, чтобы не использовать какие-либо пакеты, библиотеки или фреймворки. Почему я не воспользовался Stencil или Polymer? Мне хотелось на собственном опыте увидеть то, что способны предложить современному разработчику чистые веб-стандарты. Правда, это не относится к средствам сборки проектов.

Здесь я рассказал о том, как испробовал один из них, но он ни в коем случае не ограничивает возможности тех, кто хочет создавать приложения с минимальным использованием чужого кода. Я уверен, что существует множество подходов к разработке SPA или фронтенд-приложений без использования фреймворков или библиотек.

Базовые технологии или фреймворки?

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

Такие вот «переломные моменты» могут возникать на разных этапах жизни проекта. Если ваш проект дорос до такого уровня, то вам нужно будет решить — стоит ли вкладывать время в создание системы, реализующей те же возможности, что и некий фреймворк или некая библиотека. Но надо отметить, что фреймворки, если применять их правильно и уместно, отлично показывают себя в деле разработки веб-проектов. Это зависит от количества времени, которое есть у программиста или команды, и от объёма финансирования разработки.

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

Итоги

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

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

Уважаемые читатели! Разрабатывали ли вы веб-приложения, стремясь к минимальному использованию чужого кода?


Оставить комментарий

Ваш email нигде не будет показан
Обязательные для заполнения поля помечены *

*

x

Ещё Hi-Tech Интересное!

Интересные факты об истории Китайской лунной программы и космической миссии «Чанъэ-4»

Многое скрыто за заборами полигонов и стенами лабораторий Китайской академии космических технологий при реализации лунных научно-исследовательских космических программ, но часть информации потом все равно любезно предоставляется в открытый доступ.В продолжении этой публикации. Ранее опубликованные материалы о «Чанъэ-4»: Краткая Китайская история ...

Путеводитель по программе JPoint 2019

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