Pull to refresh

Comments 55

Спасибо за обзор.


"как изоморфные приложения отразятся на Вашей зарплате" — хотелось бы послушать и про это.


Про большой размер Bundle-JS: на самом деле можно всё распилить на небольшие чанки (отдельные куски js-кода) и грузить их динамически на клиенте через SystemJS. Webpack 2 нам поможет.


Пока что у React-а весьма плачевная ситуация с роутингом — с 2013 никто так и не осилил сделать всё по уму. Вся надежда на React Router v4. Но пока что там всё очень сыро и недоделано.


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

Про большой размер Bundle-JS: на самом деле можно всё распилить на небольшие чанки (отдельные куски js-кода) и грузить их динамически...

Ну на самом деле это далеко не волшебная пилюля. Например у меня в единственном проекте на Reat при загрузке отображается либо страница логина, либо главная страница. В любом случае для работы эти страниц надо загрузить: React, React Bootstrap, lodash, React Router, Redux. Это самые большие библиотеки в проекте и именно они составляют около 70 процентов бандла. Так что в динамическую загрузку получиться отправить только 30% бандла (а то и меньше).

Даже при таких раскладах на низких скоростях заметна разница между загрузкой страницы логина за (грубо) 4 секунды и потом главной страница за ещё 2, чем загрузка страницы логина за 7 секунд и дальше без загрузки.
Подозреваю что скоро изоморфные приложения можно будет делать на C++/Rust, подозреваю что это будет самый скоростной (в плане производительности, а не скорости разработки :-) вариант

Хоть сейчас берите Emscripten и пишите.

изоморфные приложения на с++ 20 лет назад называлось CGI.
И может я че-то не понимаю… Раньше все скидывали на клиент, чтобы сервер меньше считал. А теперь типа все назад на сервер, потмоу что ОДИН клиент не тянет. А сервер значит 1000 клиентов — легко.
И вот что ещё странно. На клиенте утечка памяти есть, а на сервере на 1000 подключений на томже самом стеке технологий не будет… Странно.
А как дебажить эти ваши изоморфные приложения???

Давайте я вам расскажу. Приложение на клиенте выполняется все время: там всякие таймеры, бэкграунд события, работа со стейтом и тд.


Сервер сайд рендеринг конвертит HTTP запрос в HTML и отдает его клиенту. Все! Поэтому он и тянет 1000 клиентов и утечек там не происходит. Задержка для обычных SPA происходит, потому что надо выкачать JS, обработать его и запустить. Здесь и проходят потеря времени. Изоморфные приложения дают контент юзеру раньше, чем обработается JS, что улучшает UX и делает ваш ресурс SEO-friendly.


Дебажать также просто — у вас код общий на клиенте и на сервере на 90+%. Так что разницы между SPA и изоморфной частью нет особенно. Тут более подробно — https://habrahabr.ru/post/309958/

А почему это все на клиенте создает утечки? Может надо бороться с утечками нормальным кодом, который не течет? При чем утечки в контексте статьи? Или течет какая то либа, которая отвечает за стейт? Ну так выкиньте ее на свалку.

Вы не правы. Суть сферических изоморфных приложений в вакууме в том, что они могут исполняться и на сервере и на клиенте. Ни 20 лет назад, ни сейчас C++ код нельзя выполнить в браузере.
Вообще говоря, если не ограничивать клиентов браузерами, то изоморфные (в какой-то степени) приложения появились чуть ли не сразу с появления клиент-серверной архитектуры. Особенно в сферах, где нормальным была длительная работа при отсутствии связи с сервером. Я такие писал ещё в 90-х.
Ага. Начинаем определяться с терминами.
Суть статьи в следующем.
Придумываем 4-хзвенную технологию.
Звено 1 — база данных
Звено 2 — сервер, которые генерит данные из базы наружу. Сейчас это можно слово «RAST»
Звено 3 — сервер, который генерит шаблон страницы в HTML с помощью js. Это костыль данной технологии — генерацию страницы уже не знаю куда приткнуть: typescript(чтобы можно было больше 3-х файлов написать коллективом более 2-х человек) + babel (потому что нужен прогресс ради прогресса без понятного результата) + framework1-2-3 (костыли для компонентной разработки, потомоу что HTML убог и примитивен). Если выйти за рамки JS, то это все всякие разные PHP/Python/CGI спокойно делают это последние 20 лет без особых заморочек.
Звено4 — браузер, который получив шаблов HTML, подгружает скрипты и страница работает.

Всяя суть статьи в том, что звенья 3 и 4 вы можете сделать в браузере. По своему желанию — или так, или так.
Только особенность технологии JS — если сделать все браузере, то он ставит современные компы на колени (напримет тотже atom за 3-4 час а рабоыт выжирает несколько Гб оперативки на паре открытых файлов по 10 кб).
Итогог, ИЗОМОРФНЫЙ = костыль JS.
Если это слово убрать, то PHP/Python/C++/Pascal + JS — тоже можно, только модные слова типа React, Angular, ES6 — проходят мимо и остается просто работа.

Кстати, судя по статьям на хабре, технология фремворков JS деградирует — ответа, на чем писать, нет даже приблизительно, есть лишь разные варианты БДСМ.

ЗЫ. Подсказываю, как и коментатор ниже — проблема в браузере как стеке технологий.
> изоморфные приложения на с++ 20 лет назад называлось CGI.
Серверная часть веб приложений на С++ и сейчас есть, это не обязательно С++. Экзотика это С++ в клиенте через наступающий WebAssembly.
В большинстве случаев не согласен с автором.

— Грамотный подход к структуре приложения. Не надо делать один большой бандл. Разбивайте приложение на пакеты и модули. Подгружайте все остальное по мере необходимости. И не будет никаких проблем с пустой страницей. К примеру у меня 10 пакетов, каждый их которых содержит 5-7 модулей. А для главной нужены только два три модуля из пакета. А когда происходит навигация — догружаете нужное.

— Проблемы СЕО. Создаем АПИ для робота и отдаем нужный контент. Да, это хак, но снимает кучу проблем. Да приходится поддерживать две точки входа, но еще ни разу не испытывали с этим проблем.

— Один код для сервера и клиента не всегда хорошо, а можно сказать плохо. Возьмем на примере микросервисную архитектуру, где микросервис может быть написан на Java/JS/Python/Ruby/PHP. Кроме JS ваш код нигде больше не пригодится. И что делать, если решили переписать, к примеру один микросервис с Node JS на Java? Приплыли с изоморфом. Пусть лучше каждая часть делает то, что хорошо умеет.

— 5% для бизнеса это крах? Ребята, оставьте «дедушек» умирать. Пусть отойдут в мир иной. И задумайтесь над поддержкой кода для «старья». Иногда овчинка выделки не стоит. Для себя давно вынес решение — никакой поддержки старых браузеров, что приносит значительную экономию по времени, а так же позволяет использовать более новые технологии без лишних полифилов.

Обычно когда речь про изоморфные веб-приложения, это не про API. Это исключительно про UI-ную часть.
API можно на чем угодно писать и дробить его на сколько угодно микросервисов.

Я, прочитав статью, поначалу расстроился за свой любимый метеор. А после вашего коммента, думаю напрасно :) Тоже, как и в комменте выше про разделение нагрузки между клиентом и сервером, очень смущает этот SSR. Хотя и в метеоре он тоже есть (пакетом с префиксом meteorhacks...). Обычно он нужен не более чем для отправки писем.

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

Для паука можно подготовить один шаблон для всех страниц — картинка, заголовок, контент (или массив контентов).
Понятно, спасибо. У меня сначала была мысль не по юзер-агенту, а через роботс.тхт и сайтмап, но это уже вариации на тему.
Вот тут подумалось (в контексте пакета meteorhacks:inject-initial).
Почему бы не отдавать сразу в html скрытый html-контент для индексации?

В целом если поразмыслить, я написал 4-5 SPA. Это именно Applications, и хоть в одном бы ешкин кошкин понадобилась бы SEO-оптимизация… так нет же… всё самое вкусное, в назовем так, «личном кабинете».
По поводу скрытого контента — не знаю. Не пробовал с такой стороны посмотреть. Возможно, кто пробовал дадут более верный фидбек об этом.

По поводу вкусняшек — самое вкусное содержит приватные данные пользователя, который бы не хотел публиковать их наружу. Если развивать тему, то SEO оптимизацию имеет смысл делать, в рамках SPA, только на блогах или магазинах к примеру. Да и там собственно логики кот наплакал.

Возьмем за основу магазин. Страница списка товаров. Страница товара. Корзина. Навигация. Поиск. Да собственно и все. Логики почти ноль, как и работы над проектом. И вообще не интересно работать с таким проектом.

Другое дело если это ERP или CRM системы. Со своей админкой, кабинетами, профилями, правами доступа итд. Вот тут SEO и нафиг не нужна. Зато здесь уже надо уделять внимание структуре проекта, оптимизации кода, бизнес логике итд.
Да, согласен. Магазины и блоги — это не приложения, там вся мощь клиентского рендеринга и не нужна особо. Возможно даже и для личного кабинета банка (но тут не факт).

Что касается отдачи скрытого контента — надо знать URL'ы, а в метеоре обычно роутинг клиентский. Так что тоже не особо вариант. В любом случае SEO-оптимизировать, скажем, канбан-доску и прочий функционал, связанный с пользовательским контентом, да, нет смысла.
Коллеги, а мне для понимания расскажите, пожалуйста — почему минусуете текст? Не расшифровывать тексты по фронтенду? Или что в этом конкретном тексте плохо?

Хороший текст, я даже для себя немного нового узнал. Правда я плюсанул :)

У темы "изоморфных веб-приложений" много ненавистников. Увы. Хотя легко понять почему, всё очень сложно программируется, сотни статей на эту тему, а на выходе всё равно у всех получается страшный клиент весом 3 мегабайта.
Но когда-нибудь скоро все проблемы и подходы к их решению будут стандартизированы, и мы будем иметь легковесные изоморфные single page application.

Изоморфность в контексте Реакта — тупиковый путь в принципе. И проблема даже не в истинной сложности (о которой стыдливо умалчивают в восторженных статьях) и весе, а в том, что на самом деле эта вся возня не дает никакого ощутимого профита по сравнению с иными подходами. А если говорить о будущем — вспомните лучше о веб-компонентах: близкое знакомство с ними ставит мозги на место и хорошо лечит Реакт-головного-мозга.

Холиварная тема в принципе. До сих пор не закончился толком холивар на тему где лучше рендерить HTML/DOM — на клиенте или сервере, а тут предлагается рендерить и там, и там. У практиков сразу всплывают минусы обоих способов.
Наверное маркетинговый bullshit и хипстота :-)

В теории все замечательно. На практике, уже с интернетом 1 Мбит пользоваться Web очень некомфортно. Когда используешь телефон в области слабого приема (Edge, а такие места встречаются очень часто даже в Московской области), можно даже не пытаться загрузить многие сайты — все равно загрузка этих гигантских бандлов либо прервется по таймауту через несколько минут, либо, что более вероятно, устанешь ждать.


За границей, где слабый Wifi или медленный и дорогой мобильный интернет, современный Web превращает жизнь в кошмар. В прошлом году мне надо было отправить перевод через Интернет-банк за границей. Я потратил на это полдня, но так и не смог дождаться загрузки интерфейса банка. Загрузка постоянно отваливалась по таймауту, все эти огромные бандлы грузятся одним куском и не кэшируются.


"Кэширование? Это какая-то технология 1999 года? У нас нет времени на это старье, мы тут переписываем свое изоморфное Redux-React супер приложение с React 14 на React 15. На наших гигабитных каналах это уменьшает время отклика на 0.001 с — гигантское преимущество, пускай и придется переписать 80% кода. Отстаньте со своим кэшированием". Как-то так получается… :(

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

А можете уточник за какой границе вам попался такой слабый вайфай и дорогой мобильный интернет?

Право, сейчас за границей и ситуация строго наоборот — вайфай везде и бесплатно, 4G на телефоне и стоит копейки.

Ну, конкретно проблема с банком была в Индии. Я знаю, что в Индии едва ли не самый медленный интернет в мире. Но на мой взгляд это не оправдывает хипста-сайты, которые сейчас везде. Если в Индии их просто загрузить невозможно, то в России, например, это просто некомфортно. Во-первых, очень долго. За городом у меня интернет 1 Мбит, и очень многие сайты ощутимо тормозят. Более быстрый интернет обойдется мне значительно дороже.


Многие тарифные планы для мобильных имеют ограничения по трафику. Не знаю почему, но по опыту все эти React-Redux-куча-прочих-buzzwords приложения каждый раз загружают эти бандлы заново. Может быть React требует внесения изменений в приложение каждые полчаса. Не знаю. Но трафик это подъедает заметно, и скорость загрузки тоже сильно страдает.


В принципе понимаю, что нет в жизни счастья, и надо раскошеливаться на новый интернет-канал на даче, лучше ситуация не станет. А за границей надо планировать все так, чтобы не понадобилось заходить в интернет-банк. Просто удивляет, что все это преподносится как супер-дупер технологии, которые улучшают время загрузки и отклика, а по моему опыту как пользователя — все совсем наоборот. Страницы стали тяжелыми, медленными и хрупкими (то есть, если скорость канала чуть ниже какой-то критической, субъективно менее 1 Мбит, то все эти SPA начинают подвисать, глючить, ломаться).

Собственно для этого и придумали изорморфные приложения: сначала грузится HTML, а потом уже все эти новомодные фичи

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


А даже если и загрузятся, то ни одно из новомодных приложений не проверятся на то, как оно будет вести себя на плохом канале связи. В итоге нередко бывает, что кнопки не нажимаются, формы не работают, и т.д. и т.п., потому что приложение предполагает, что любая коммуникация с сервером завершается успешно (потому что у разработчиков сервер на той же машине, или рядом, на 10 Гбит канале), шлют по сети гигантские JSON-блобы, которые опять же либо теряются, либо приводят к таймауту, а эти ситуации никак не предусмотрены в приложении. Некогда их предусматривать, новая версия Redux вышла. Или FooBarQuux, который в тыщщу раз круче, чем Redux.

А с чего вы взяли, что в случае нормального изоморфного приложения нужно ждать загрузки бандла? А как же Progressive Enhancement?

Я это взял с того, что часто нахожусь в местах, где медленный интернет. Там все эти модные SPA работают из рук вон плохо. Progressive Enhancement — все понимают, что это хорошо, но никто не делает. Например, один из российских банков отображает страницу ввода пароля до загрузки бандла, но если до полной загрузки ввести пароль, то получаем ошибку. Впрочем, раньше эта страница весила 18 Мб или больше, и дождаться ее загрузки по Edge соединению где-нибудь в Индии было просто невозможно.


У остальных все приблизительно так же. Если не находишься на быстром соединении (как минимум 3G/4G), то любым из современных сайтов пользоваться почти невозможно, включая даже не особо динамические GT и Habrahabr — почему-то часто начало страницы начинает отображаться, а затем браузер заменяет ее на страницу о невозможности загрузки. Как им это удается, не понимаю....


Даже если SPA загрузилось, то оно не работает на медленном соединении. Кнопки не нажимаются, формы не отправляются, возникают ошибки одна загадочнее другой.

То что никто этого не делает — это другой вопрос. Технических проблем делать все по уму не существует. Нет никакой супер веской причины ждать загрузки JS бандла, чтобы изоморфное приложение работало, кроме лени разработчиков.

Ну что поделать, мир несовершенен. Любая технология, которую можно использовать неправильно, будет использована неправильно.


Из этой же серии приложения на Electron. Простой чатик будет выжирать 2- Гб памяти, и процентов 20-40 CPU. Если же необходимо несколько таких приложений, то к ноутбуку надо будет прилагать батарею Tesla и промышленный вентилятор для охлаждения. Но поток SPA и Electron-приложений это не останавливает, к сожалению.


У разработчиков SPA нет никаких мотивов, чтобы делать небольшие приложения с поддержкой progressive enhancement. Люди, как я, которые много времени проводят в местах с плохим интернетом, не приносят их бизнесу достаточно прибыли, чтобы оправдать правильное написание/оптимизацию.

Можно использовать неправильно и использовать неправильно это все же разные вещи.

В своем комментарии, вы безапелляционно написали, что мол пока не загрузится бандл ничего сделать будет нельзя. Я в свою очередь написал, что это сильно зависит от разработчиков приложения и сама по себе такая возможность есть. И кстати говоря, нужно приложить не так уж и много усилий для того, чтобы обеспечить должный уровень progressive enhancement. Проверено на собственном опыте.

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

У разработчиков SPA нет никаких мотивов, чтобы делать небольшие приложения с поддержкой progressive enhancement.

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

Спасибо за очередной интересный доклад. Вот только я что-то так и не понял зачем нужен отдельный frontend-сервер, это же было до SPA, что сервер сам генерил HTML и отдавал в браузер, теперь получается тоже самое, только с посредником? Или я что-то не так понимаю?

Вся соль в том, что frontend-сервер и frontend-клиент теперь могут иметь 90+% общего кода.

А зачем нужен отдельный frontend-сервер, в чем его необходимость в данной архитектуре?

Классические SPA не дружат с поисковиками и индексированием (есть костыли, но они плохие). А изоморфные, благодаря серверному рендерингу, дружат.

А еще серверный рендеринг ускоряет визуализацию контента в браузере. Т.е. сначала, скажем, отдается 50кб html+css. Пользователь их сразу видит и может уже читать страничку, тыкать по ссылкам и т.д… А только потом уже незаметно для пользователя подгружается тяжелый js-bundle.
Это быстрее чем классические SPA, которые сначала показывают пустую страницу, потом тянут js-bundle целиком, и только потом пользователь что-то видит в браузере.

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

Ну идея про 90+% общего кода точно классная. В теории это легче и дешевле поддерживать будет. Особенно для крупных проектов.
На практике неясно, пока всё только устаканивается. Проблем хватает.

А зачем вообще клиентский код, если возвращаемся к серверному? Это ж все придумывали ради оффлайна и аякса. Теперь всё это не надо?
Теперь совмещают преимущества серверного и клиентского рендеринга избавляясь от их недостатков за счёт дублирования кода рендеринга. Ну или пытаются совмещать и избавляться, но плохо получается.
90% общего кода получается при более-менее сложной логики только при выделении отдельного фронтенд-сервера для серверного рендеринга и шлюза к бэкендам. 90% — рендеринг HTML/DOM по адресу, 10% кода на клиенте — обработка UI событий (кроме событий адресной строки с потерей контекста) и запросы к серверу, 10% кода на сервере — трансляция запросов клиента к бэкенду. Основная логика — на бэкендах.
1. Обеспечивает отдачу статики, включая тяжелые JS для SPA-функциональности
2. Обеспечивает отдачу отрендеренного HTML по URL (первый заход, поисковые и прочие боты, ориентирующиеся на HTML)
3. (опционально) Служит для SPA шлюзом и агрегатором бэкенда

За эволюцией веб-сообщества можно наблюдать бесконечно. Вот примерная история:


  • сервер отдает статический хтмл и ресурсы, просто и идиоматично
  • появился PHP, а давайте возвращать хтмл динамически
  • Js/JQuery, зачем возвращать хтмл динамически, если можно не заставлять юзера ждать перезагрузку страницы
  • только js/SPA, см. п.1 (сервер отдает статический хтмл и ресурсы)
  • А давайте снова возвращать хтмл динамически
  • (будущее) непонятный баланс между мнгновенным открытием сайта и устанавливаемыми веб-приложениями
Сейчас работаю frontend-разработчиком на проекте с классической архитектурой, где весь HTML генерируется PHP-фреймворком, однако настроен в будущем это изменить, написав соотв. изоморфное приложение. Но так как времени на конкретно эту задачу никто не выделит, задался вопросом, возможно ли внедрение в HTML, генерируемый PHP, кусочков отрендеренных на JS? Чтобы осуществить постепенный переход к «светлому будущему». Есть у кого-либо подобный опыт, возможно есть статьи, описывающий такой подход?
Возможно. Поднимаете сервер на JS, который рендерит то, что нужно, а в шаблонах PHP делаете (самый простой способ, если есть доступ к настройкам сервера и понимание последствий в плане безопасности прежде всего) что-то типа
<?php require 'http://js-server/needed-url' ?>

Для Symfony есть бандл, который делает это более секурно и гибко, может использовать как рендер-сервер, так и запускать node как обычный процесс.
P.S. В своём проекте я пошёл по другому пути. Маршрут обычного запроса на показ страницы:
1. пользователь вводит адрес
2. браузер делает запрос на nginx
3. nginx проверяет есть ли статика, удовлетворяющая запросу
3.1. если есть — отдаёт
3.2. если нет — проксирует на js-сервер
4. js сервер проверяет может ли отрендерить результат сам (возможно обращаясь к php-серверу по API)
4.1. если есть — рендерит
4.2. если нет — проксирует на php-сервер
5. php-сервер обрабатывает запрос обычным путём
Значительно ли падает время ответа сервера на запрос при таком подходе?
Незначительно. По сути на размер пингов от nginx до js и от js до php в случае если рендерить должен php (естественно в предположении, что у js ничего надолго поток не захватывает, всё асинхронно). На проде у нас это максимум два физических хоста в одной стойке, а часто и просто два процесса (докер-контейнера) на одной виртуалке.

Если критично, то можно роутинг сделать на nginx, чтобы он по урлу и прочим параметрам запроса определял куда направлять запросы на js или php. Но это поддерживать сложнее — нужно внедренные на JS-сервере фичи не забывать описывать в конфиге js.
Большое спасибо вам за советы!
Sign up to leave a comment.