Пользователь
0,0
рейтинг
24 ноября 2013 в 20:13

Разработка → Изоморфный JavaScript — будущее веб-приложений перевод

В компании Airbnb мы многому научились за последние несколько лет, создавая мощные веб-приложния. Мы погрузились в мир одностраничных приложений в 2011 г., делая мобильную версию нашего сайта, с тех пор, кроме прочего, мы запустили Wish Lists и новый поиск. Все это — большие JavaScript приложения, что означает то, что тонны кода запускаются в браузере, чтобы обеспечить современный интерактивный пользовательский опыт.

Это обычный подход сегодня, когда такие библиотеки, как backbone.js, ember.js и angular.js помогают разработчикам создавать мощные JavaScript приложения. Мы поняли, однако, что такие приложения имеют несколько критических ограничений. Чтобы стало понятно, давайте предпримем небольшой тур по истории веб-приложений.

Картинка из статьи для привлечения внимания


JavaScript взрослеет


На заре Веб взаимодействие с браузерами было таким: веб-браузер запрашивал каждую страницу (например, www.geocities.com) заставляя сервер, находящийся где-то в Интернете генерировать HTML, и отсылать обратно. Этот был хороший подход, так как браузеры в то время были еще не особенно мощными, да и HTML-страницы, в основном, были статичными и автономными. JavaScript, созданный чтобы позволить веб-страницам быть более динамичными, не позволял сделать что-либо более сложное чем слайд-шоу или виджет подбора даты.

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

Одностраничные приложения


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

О библиотеках типа backbone.js, ember.js и angular.js часто говорят как о клиентских MVC или MVVM библиотеках. Классическая клиентская MVC архитектура выглядит примерно так:

image

Большое количество логики приложения (представления, шаблоны, контроллеры, модели, интернационализация и т.д.) живет на клиенте, для данных используется специальное API. Сервер может быть написан на любом языке, таком как Ruby, Python или Java. В большинстве случаев их роль заключается в отдаче каркасной страницы. Как только JavaScript файлы загружаются браузером, они выполняться, клиентское приложение инициализируется, подгружаются данные через соответствующее API и отрисовывается оставшаяся часть HTML.

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

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

Неприятности в Раю


На практике, однако, у этого подхода есть несколько фатальных недостатков, которые не позволяют его использовать во многих случаях.

Поисковая оптимизация

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

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

По той же самой причине, если сервер не генерирует страницу целиком, а вместо этого приходится ждать загрузки JavaScript на клиент, пользователи несколько критических секунд видят пустую страницу или значок загрузки. Проводилось множество исследований изучающих то, какой эффект оказывают медленные сайты на пользователей, и, соответственно, на прибыль. Amazon утверждает, что каждое 100 мс сокращение загрузки увеличивает прибыль на 1%. Twitter потратил год совместных усилий 40 разработчиков переделывая сайт, чтобы генерировать страницы целиком на сервере вместо клиента, получив 5-кратное улучшение воспринимаемого времени загрузки.

Поддержка

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

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

Гибридный подход


В итоге, нам нужен гибрид нового и старого подходов: мы хотим получать полностью сформированный HTML с сервера по причинам производительности и SEO, но нам нужны так же скорость и гибкость приложений клиентской стороны.

Чтобы добиться этого, мы, в Airbnb, экспериментируем с «изоморфными JavaScript приложениями», JavaScript приложениями, которые могут работать как на клиенте так и на сервере.

Изоморфное приложение выглядит примерно так. Озаглавлено “Клиент-серверное MVC”:

image

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

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

Изоморфный JavaScript в дикой среде


Идея не нова — Nodejitsu сделал хорошее описание архитектуры изоморфного JavaScript еще в 2011 г. — но она была трудно адаптируемой. С тех пор появились еще несколько изоморфных фреймворков.

Mojito был первым известным изоморфным фремворком с открытыми исходными кодами. Это продвинутый, фулстек-фреймворк, основанный на node.js, но он зависел от yui, да и причуды yahoo не способствовали его особой популярности в JavaScript сообществе с момента, как он стал открытым в апреле 2012 г.

Meteor — вероятно самый широко-известный изоморфный проект сегодня. Метеор создан с нуля для поддержки приложений реального времени, и его команда создала целую экосистему вокруг своей пакетной системы и инструментов развертывания. Как и Mojito, это большой, чрезмерно самоуверенный node.js-фреймворк. Однако многое было сделано для привлечения JavaScript-сообщества, и их наиболее ожидаемый релиз 1.0 уже не за горами (прим. пер. в начале 2014 г.). Метеор — это проект за которым нужно следить — звездная команда, $11.2 млн. финансирование от Andreessen Horowitz — неслыханно для компании, полностью сфокусированной на выпуске продукта с открытыми исходными кодами.

Asana, приложение по управлению задачами основанное Facebook с со-основателем Дастином Московицем, имеет интересную изоморфную историю. Не испытывая проблем с финансированием, учитывая статус Московица, как самого молодого миллиардера в мире, Асана провела годы исследований, разрабатывая свой фреймворк Luna с закрытыми исходными кодами — один из самых продвинутых примеров изоморфного JavaScript. Luna, изначально созданная на v8cgi (в дни предшествующие node.js) позволяла запускать копию приложения на сервере для каждой пользовательской сессии. Для каждого пользователя запускался отдельный серверный процесс, выполняя тот же JavaScript-код который запущен на клиенте. Это давало все преимущества продвинутой оптимизации, такие как устойчивость к оффлайну и быструю реакцию.

Мы тоже создали свою изоморфную библиотеку в этом году. Называется она Rendr. Она позволяет создавать backbone.js + handlebars.js одностраничные приложения, которые так же могут полностью формировать страницы на сервере. Rendr — это результат нашего опыта переделки мобильной версии Airbnb для улучшения скорости загрузки, что особо важно для мобильных пользователей которым свойственны высокие задержки при передаче данных. Rendr — скорее библиотека, чем фреймворк, решающий несколько задач (если вы будете сравнивать с Mojito или Meteor), но он легок для изменения и расширения.

Абстракции, абстракции, абстракции


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

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

Нам нужен единый набор маршрутов, которые сопоставляют определенные URI-шаблоны соответствующим обработчикам. Этим обработчикам должны быть доступны: HTTP заголовки, куки, информация из URI и возможность перенаправления без прямого доступа к windows.location (в браузере) и req и res (в node.js).

Загрузка и сохранение данных

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

Генерация страницы

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

Сборка и упаковка

Оказывается написание изоморфного кода приложений — это только половина дела. Инструменты, такие как grunt и browserify — неотъемлемая часть процесса создания и запуска приложений. Для сборки обычно нужно выполнить несколько шагов: компиляция шаблонов, включение клиентских зависимостей, применение трансформаций, минификация и т.д. В простейшем случае нужно собрать весь код приложения, представление и шаблоны в единый пакет, но для больших приложений, это может обернуться необходимостью передавать сотни килобайт клиенту. Более продвинутый подход — это создать динамическую связку и предоставить возможность отложенной загрузки, однако в этом случае сложность быстро возрастает. Инструменты статистического анализа кода, такие как Esprima позволяют честолюбивым разработчикам провести продвинутую оптимизацию и метапрограммирование, чтобы уменьшить количество шаблонного кода.

Собираем из маленьких модулей


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

Очевидно, что большинство JavaScript-модулей могут уже быть использованы изоморфно либо без, либо с небольшими модификациями. Например, такие популярные библиотеки, как undrscore, backbone, handlebars, moment и даже jquery уже можно использовать на сервере.

Чтобы продемонстрировать все это, я создал небольшое приложение, названное изоморфный туториал которое вы можете взять с GitHub. Комбинируя вместе несколько модулей, каждое из которых может быть использовано изоморфно, довольно просто создать небольшое изоморфное приложения в сотню строк кода. Здесь используются: Director для серверной и браузерной маршрутизации, Superagent для HTTP запросов и handlebars для шаблонизации, все это собрано поверх обычного express.js приложения. Конечно с ростом сложности приложения, нужно будет добавлять дополнительные слои абстракции, но я надеюсь на то, что чем больше разработчиков будут экспериментировать с этим подходом, тем больше новых библиотек и стандартов будет появляться.

Оглядимся


Чем больше организаций будут запускать node.js в продакшен, тем неумолимей это будет приводить к тому, что все больше и больше кода будут разделяться между клиентом и сервером. Важно помнить, что изоморфный JavaScript можно использоваться и локально для узких и для широких задач — можно начать с разделения шаблонов, продвигаясь дальше до разделения всей подсистемы отображения, и завершая полным разделением бизнес логики приложения. Конкретный способ разделения JavaScript между средами целиком зависит от того как приложение создается и от его особенностей.

Nicholas C. Zakas отлично описал то, как по его мнению в приложениях произойдет переход UI-слоя с клиента на сервер, давая выигрыш в производительности и лучшую поддержку. Чтобы использовать изоморфный JavaScript, не нужно будет отказываться от существующего бэкэнда и заменять его node.js, выплескивая ребенка вместе с водой. Вместо этого, создавая правильный API и используя RESTful-подход, традиционный бэкенд может спокойно жить рядом с node.js.

В Airbnb мы уже начали переделывать процесс создания клиентской стороны, используя базирующиеся на node инструменты, такие как grunt и browserify. Наше основное rails-приложение может быть никогда и не будет полностью вытеснено node.js, но, используя их вместе, становится даже проще разделять определенные части JavaScript между окружениями.
Перевод: Spike Brehm
Артур Заяц @zag2art
карма
185,7
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (75)

  • +7
    я смотрю на все это и мне странно. я не очень понимаю зачем нужно запускать jquery на сервере, для рендеринга страниц? я не вижу в этом никакого смысла. я предпочитаю logic less шаблоны, типа mustache (hogan, handlebars), потому что позволяет делать рендеринг везде с любым бэкендом (даже у хендельбарс достаточно много имплементаций на разных языках). И просто все рисуется — или есть данные — рисуется или нет — не рисуется, всё, и никакой нужды в исполнении jquery и клиентского кода на сервере я не вижу.

    потому, что везде сейчас REST, что значит отсуствие состояния между запросами. на клиенте же состояние есть, а с сервера состояние сгенерированное не передать, кроме как в виде html (json), и весь профит от этого пропадет (проиницилизированные компоненты например не передадутся же).

    извиняюсь за скомканость, но мне кажется это не сколько бессмысленным.
    • +2
      Про jquery на сервере вы конечно же правы, а вот про бессмысленность общего подхода — не совсем. В Atma.js используем компонентный подход к построению приложения и у нас есть 3 возможных типа рэндеренга компоненты — клиент, сервер или «изоморфный». Клиент — здесь всё просто и всё как вы знаете из бэкбона, ангулара — стандартный mvc шаблон. Сервер — также довольно просто — как вы описали, есть модель и шаблон — генерируем html. Серверный подход используем редко, лишь тогда, когда нужно скрыть модель и компонент от клиента в целом. А вот изоморфный метод рэндеринга передает не только html клиенту но и небольшую мета информацию по атрибутам компоненты в виде html комментария. На клиенте же создается новый экземпляр (`instance`) компоненты — навешиваются dom-события, присваивается модель, создается дерево компонент и прочее. В таком подходе несколько плюсов — 1) Клиент получает html (`seo-/scriptless-friendly`). 2) Выигрываем в производительности, так как никакого построения DOM больше на стороне клиента нету. 3) Этот же компонент можем использовать только на клиенте в дальнейшем рэндеринге.

      Объяснил возможно немного сумбурно, но `профит` в этом огромный.
      • 0
        Что-то я запутался в этом круге. сео-готовый hml-изоморфный… Оно исключает другое. Если нам нужен сео и мы начинаем генерить олд-стайл html на сервере на гуглобота, то… зачем нам все остальное? Точнее оно становится невозможно, т.е. генерим по старинке тем же пхп. И наоборот. Можно как-то по другому объяснить или какой-то простой пример как это может жить все вместе и какой огромный профит?
        • +3
          Профит от использования может быть в том, что клиент и сервер могут использовать общие куски кода (модели валидации данных как самый очевидный пример). И не обязательно при этом запускать на сервер-сайде фреймворк вроде jQuery, на сервер-сайде будет свой фреймворк, написанный на node.js. Общий код по идее не должен входить ни в то, ни в другой фреймворк, но с легкостью подключаться к обоим (очевидно этого можно добиться, если обе части написаны на одном языке программирования).

          Я давно пытаюсь найти более полезное применение (помимо общего куска кода для валидации данных) этой интересной идее, но никак не получается. Круг задач, которые решают сервер и клиент, и методы их решения настолько различны, и общего кода получается настолько мало, что нет практически никакого смысла в предпочтении на стороне сервера node.js вместо php/python/ruby/java. Мало того, javascript сильно отличается от упомянутых языков программирования, что в большинстве случаев приводит к увеличению объема кода, который требуется написать на нем для решения типовой задачи, по сравнению с классическими объектно-ориентированными подходами.

          Может кто-нибудь может поделиться ссылкой на подробный материал либо просто перечислить ситуации, где такой подход будет уместен/полезен?
          • +1
            Предлагаю всем желающим взглянуть на фреймворк derbyjs, недавно так хорошо описанный vmakhaev. Там созданы абстракции как раз такие, как описывается в статье. Архитектура изоморфна — точь в точь как на 2-ой картинке. Вы пишете приложение, которое работает и на клиенте и на сервере, со всеми плюсами, описанными в статье. habrahabr.ru/post/196144/

            Еще я лично собираюсь поиграться с "изоморфным туториалом"… Да и модули интересно посмотреть как написаны, тот же director
            • 0
              Действительно, дерби замечательный фреймворк, единственное только что смущает, они через чур привязываются к бэкенду — будет не очень просто переделать под stand-alone приложение, скажем для phonegap. Или я ошибаюсь?
              • 0
                К сожалению ничего не знаю про phonegap, но вашу мысль насчет чрезмерной привязки к серверу все равно не понимаю. Почему вы так думаете? Есть там пару моментов, которые меня смущают: жесткая привязка к redis и mongo на данном этапе, и невозможность сделать приложения вообще без серверной стороны. Вы об этом?
                • 0
                  Да, именно о невозможности сделать вовсе без сервера. Скажем на случай, если уже имеется derbyjs вэб приложения, но клиент захотел ещё мобильное приложение. Вот и интересно, как сложно переделать под phonegap. Я читал, они собирались как-то избавится от этого ограничения, но или уже сделали или нет, не знаю.
                  • 0
                    Архитектурно вместо mongo всегда конечно можно minimongo на клиенте, из всех клиентские либ сразу собрать бандл, но у них сейчас проблема в том, что они используют redis для журналирования и pub/sub и пока без него никак — вроде хотят разделить эти функции, посмотрим.
                  • +1
                    Начиная с версии 0.6, которая выйдет через месяц-два вы сможете использовать клиентскую часть Derby отдельно от серверной. Что позволит использовать Derby, в том числе и в Phonegap. Хотя некоторые умельцы делают это уже сейчас: github.com/psirenny/derbygap
                    • 0
                      О! Главный специалист по derby. Жду твоего развернутого мнения по сабжу :)
                    • 0
                      Будем ждать, код у них действительно качественный, интересно посмотреть как они все реализуют. Предложенный вариант умельцев лишь генерирует статические файлы из страниц сервера. Выход конечно, но не совсем оптимальный.
          • +1
            Присоединяюсь к этому мнению — допускаю и понимаю что возможен теоретический профит, но практически грош ему цена.
            • 0
              А зачем же тогда Твиттер так старался генерить страницы на сервере (год 40 программистов делали серверный рендеринг на scala)?
              А если бы у них изначально архитектура была изоморфной, то не понадобилось бы так напрягаться… Разве нет? Вот и профит.
              • 0
                у них ренедеринг не обязательно на скала, это раз, во вторых они просто шаблоны шаблонизируют, никакой магии там нету, у них hogan — реализация мусташь — на клиенте, на сервере обычные мусташ. год они делали не сервер сайд рендеринг, год они делали нормальную архитектуру на клиенте (см. twitter flight), отказываясь от повсеместнораспространнеых решений в виде очередной реализации громоздкого mvc. посмотрите видео с конференций, они много выступают, в том числе фронтенд разработчики.
                • 0
                  Подробностей не знал — посмотрю.
        • 0
          > Оно исключает другое

          Это не так. И в статье именно об этом и говориться. Основная мысль такая — можно так выстроить приложение, чтобы код генерации страниц работал абсолютно одинаково, вне зависимости от того где его запустили.
          • 0
            я все же не понимаю зачем нужен jquery на сервере для рендеринга
            • 0
              Тоже думаю не нужен. Я вообще больше к декларативным вещам тяготею, типа того же angular-а. А jquery автор наверное упомянул для контраста, типа «даже такая изначально клиентская штука, как jquery в принципе может работать и на сервере». (хотя опять же, я тоже не знаю нафига она там нужна...)

              Суть статьи же не в jquery.
              • +1
                angular.js клевая штука, но мне не нравится тем что все в декларативные шаблоны выносит, ну в смысле то что вообще все. плюс делает невозможным серверсайд рендеринг без «эмуляции» браузера. тот же react от фэйсбука продвигают как фрэймворк с возможностью server side рендеринга, но я тяготею к твиттер флайту и сделал несколько проектов (и делаю) с ним, в полном восторге. сочетая его компонентную (там вообще что то типа АОП на акторах) структуру с методолгией БЭМ получается делать все абсолютно безболезненно и просто поддерживаемо. хотя иногда хочется магии из ангуляра
                • 0
                  Согласен на счет недостатков angular-а, отсюда и поиск новых форм, типа того же изоморфного JavaScript и т.д. А твиттер флайт умеет рендерить на сервере?
                  • 0
                    с другой стороны зайдите.
                    помните, то что backbone очень минималистичный, из коробки доступно почти ничего?
                    так вот, твиттер флайт — еще более минималистичный, по объему кода еще меньше. у него нету привязки к какому либо шаблонизатору — и не обязательно вовсе. например на одном проекте с ним рендеринг ВСЕГО происходит на сервере, даже того что подгружается асинхронно. Сделано это из соображений простоты (ну и на самом деле так много кто работает, например basecamp, github (вроде частично) и вконтакте (в большинстве мест)). На других — разные шаблонизаторы, в основном handlebars. которые имеют реализацию под многие языки, и рендерить можно на чем угодно. вообще я давно собираюсь написать пару статей по флайту, но никак времени не найду, но уже успел некоторое число людей на него перевести :)
                    • 0
                      Ну понятно, и так уже оффтопик, надо будет посмотреть. А вы время пожалуйста найдите :) — было бы интересно.
          • 0
            код генерации страниц работал абсолютно одинаково, вне зависимости от того где его запустили.

            На клиенте часто используют Angular.js/Knockout.js и т.п. (для «интерктивности») на сервере же другая задача — по быстрому построить статический «html-текст», а имитировать работу клиента на сервере может быть (очень) затратно, и может быть не оправдано если большая часть «генераций» происходит на сервере.

            Если «формирования» на сервере необходимы редко (из за seo) для веб приложения, вот для этого можно имитировать клиента для получения страницы, и нет необходимости переводить сервер на js.
        • +1
          renskiy хорошо ответил о общей кодовой базе. По сути в этом то и смысл. Что бы не было разделения — например, это мы пишем на symphony, а это будет в angular. Я как раз сейчас для большой статьи о гибридном javascript подготавливаю одно хорошее приложение. Ну а что бы на пальцах объяснить, возьмем такой пример компоненты — имеется короткий список записей за последнюю неделю с ссылками на сами записи. Говоря о приложении, я также подразумеваю целую композицию компонент, то есть наш список с записями может находится в другой компоненте — активность за неделю, где будут еще списки с твитами и прочее. Но и не просто это отображается, но и нужна какая-то не хилая динамика в этом всем — например, добавили запись, и в список автоматически добавился новый пункт. Так вот, думаю вы согласны, что на клиенте angular/backbone или другой какой фреймворк обязателен, иначе на jquery довольно скоро появится каша. Также в большом приложении есть две основные стадии — runtime и load time. Кстати, изоморфный javascript избавляет нас от `single-page application`, которое превращается в multi-page application.

          И вот если пользователь попал в screen, где помимо других находится и наш компонент с активностью за неделю, из рантайма, то тут всё просто RESTful API + нужные контроллеры/директивы = вот и наш список. Но как быть если пользователь попал непосредственно по урлу в этот самый скрин — здесь мы уже имеем load time приложения. Использовать restful api снова? Но у нас же не один компонент который жаждет получить свою модель, а много запросов на сервер и при load time это огромные минуса в производительность. Предлагали собирать с помощью php? Но у нас же целая композиция компонент/директив с их шаблонами — как этим всем ещё отдельно управлять из php? Долгое время мы нужные данные встраивали непосредственно в html, а также пытались компоновать все запросы компонент в один, но и в таком подходе было через чур много головной боли, не нужного кода и дополнительный render overhead на клиенте. Также немаловажным здесь является и сео — паук не может проиндексировать наш список записей например. А вот с node.js мы вздохнули с облегчение. При load time компоненты «сами себя» генерируют и клиенту отдается уже готовый html, клиенту также отдается код нужных компонент и они там «сами себя» инициализируют для дальнейшей динамики в рантайме. Таким образом и производительность на клиенте лучше, и для сео хорошо, и кода меньше — разве не хорошо? Возможно снова плохо объяснил, давайте какие-то моменты лучше опишу. Это будет также полезным для будущей статьи, что бы понять, что людей смущает в гибридном javascript.
          • 0
            людей (меня например) смущает в гибридном жс, то, что ни капли не сложнее приготовить тоже самое без запуска виртуального браузера на сервере. мне нравится использовать node.js, но я не вижу никакой проблемы отрендерить то что мне нужно на сервере написав бэкенд на любом языке, для которого есть реализация использумого шаблонизатора.
            • 0
              Про виртуальный браузер вы утрируете — в нашем случае это небольшая библиотека для генерации дерева нод и компонент (компиляция шаблонов), из которого потом создается html для клиента. Также вы затрагиваете лишь одну маленькую часть приложения — рендеринг шаблонов. А как быть с директивами/компонентами которые имеют свой под-шаблон в котором определяются другие компоненты с другими шаблонами? Также каждая компонента может определять свою модель. А такое разделение обязательно — HMVC отличный паттэрн, и этим путём идут многие, ангулярные директивы, web components, enyo. Код приобретает лучшую структуру, легче внедрять компоненты в систему, легче налаживать взаимодействие компонент, легче разрабатывать — в этом мы уже убедились на опыте. Поэтому на сервере не просто шаблонизатор должен быть, а библиотека которая умеет инициализировать нужные компоненты и давать им возможность определять или переопределять свой шаблон или свою модель и это всё в древовидной структуре.
              • 0
                я согалсен про компоненты, в своем текущем проекте я возвел это в абсолют и получил очень много профита. но вы мне расскажите как рендерить приложение на ангуляр на сервере без запуска phantom.js? :)
                • 0
                  К сожалению про ангуляр не скажу, мы используем кое что получше :) У нас свой фрэймворк который «возводит в абсолют» компоненты — все шаблоны компонент-ориентированые, вот там мы и используем все прелести рендеринга на сервере или на клиенте. С примерами и документацией не густо, но вот пример лишь клиентской части — todomvc, а здесь простой правда и старенький, но гибридный подход.
            • 0
              … и вы не поймите меня не правильно, я не утверждаю, что это единственное верное решение всех проблем, это всего лишь техника и ничего более ;)
      • 0
        Этот же компонент можем использовать только на клиенте в дальнейшем рэндеринге.


        Просто где-то еще используются, или при дальнейшем рендеренге можно как-то реюзать DOM, построенный по полученному от сервера html?

        Т.е. хочется отрендерить шаблон на сервере, отправить получившийся html вместе с вьюмоделью в JSON на клиента, проинициализировать MVC-движок передав ему DOM и JSON модели, и дальше уже жить как обычно — менять модель и движок будет сам обновлять DOM.
        • +1
          Верно, всё как вы описали — при инициализации передается дом и модели которые десериализуются из json, поэтому компоненты далее работают, как будто они сами рэндерили шаблон на клиенте. А про дальнейший рэндеринг — это я имел ввиду, к примеру, если у нас есть компонент из списка каких-то данных записей — EntryItem — у него свой шаблон, свои события, прочее, ну вы понимаете. И вот в рантайме добавляется новая запись и нам не нужно рендерить её на сервере, передали json и отрэндерили уже на клиенте.
    • 0
      jquery здесь для красного словца, она не нужна. Многие изоморфные фреймоврки используют handlebars, тот же meteor, derby, авторский Rendr и «изоморфный туториал».

      По поводу REST в статье тоже все отлично сказано — стандартный бэкенд с рестфул апи остается, рядом появляется слой с node.js — читайте статью Николаса Закаса — здесь.

      Все это есть в статье.
      • 0
        читал, и она не много о другом, по моему.
        кстати «уи слой» используют яндекс (бем тулзы на node.js) и mail.ru (в почте по крайней мере).
        для яндекса — это хороший способ отделить фронтенд разработчиков от бекенда.
        для мэил.ру — ускоронение рендеринга (поищите, на хабре статья была).
        и да отделить слой рендеринга в отдельный «сервис» внутри приложения — это часто хорошо, точнее даже так, делить на отдельные «сервисы» всегда лучше чем огромный монолитный каркас.
    • 0
      Полностью с Вами согласен на тему REST. Основная идея в том, что благодаря подходу single-paged-apps мы можем использовать веб как один из множества клиентов, через REST. Завтра добавляем нативные iOS и Android приложения — не требуются никакие изменения на сервере, плюс отсутвие состояния дает нам возможность к масштабированию.
      Вообще, есть такое впечатление, что мир програмного обеспечения пытается перетянуть короткое одеяло между клиентом и сервером. Раньше был JSF/JSP/GWT которые говорили: «Ты знаешь Java? Великолепно, теперь будешь писать клиент на родном языке», теперь мы тянем это же одеяло с другой стороны «Ты знаешь JS? Пиши сервер на Node.js», все из за желания сэкономить на специалистах. ИМХО это не выйдет, все равно надо будет брать на работу двоих.
  • 0
    Нужен пакетный менеджер для клиентской стороны, чтобы собирать пакеты так же легко, как и для сервера. Либо средство адаптации пакетов npm-а (что избавит от необходимости пересоздания npm).
    Пока что изучал browserify, bower, component, все весьма поверхностно.
    • 0
      Те решения, которые видел я используют для сборки browserify, кроме метеора, он чем-то своим бандлы делает. С помощью Browserify как раз и становится возможным использовать npm пакеты на клиенте.
    • 0
      Про browserify — вот интересная статья.
      • 0
        Почему browserify не ок для приложений — есть хорошая статья.
        • 0
          А ваш Lmd может динамически подгружать commonjs модули?
          • 0
            Может, но по хорошему вы не должны этого хотеть. Лучше иметь предсказуемую загрузку и делить приложение на крупные логические куски.
            • 0
              > Лучше иметь предсказуемую загрузку и делить приложение на крупные логические куски

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

              А спросил я потому, что в вашей статье указаны 2 недостатка browserify:

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

              Или есть еще недостатки?

              Как я понял первый пункт про «не commonjs» модули. Правильно? Если так, то в browserify есть browserify-shim — это обертка для них — довольно удобная.

              По второму пункту я уже сказал. Бандлов можно сделать несколько, а вот динамическую загрузку придется делать чем-то другим.
              • 0
                а еще есть deamdify который автоматом amd модули компилит
              • 0
                — адаптация: browserify-shim — хорошая штука, но чинит не все, например, не умеет подменять this, но это может быть исправлено.
                — относительные пути: ФС нет в браузере и соответственно пути ../../models/user не нужны. Вместо них можно использовать абстрактную ФС и подключать вот так models/user или modelsUser. И соответственно можно помешивать куски чужой абстрактной ФС в вашу сборку и использовать их как вам удобно.
                — в LMD проще подключать динамические модули в сборку.

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

            Прекрасно понимаю для каких вещей лучше использовать браузерифай, а для каких нет ;) Компиляция нодовых модулей — да; Веб приложения(SPA) — нет;

            определять зависимости по конфигу?
            Не зависимости, а правила именования модулей в вашем проекте и группировку модулей по бандлам плюс тюнинг LMD под ваши нужды.
            — Конфиг в том или ином виде не избежен потому, что нельзя без полировки натянуть нодовую модульную архитектуру на особенности веб-приложений. В браузерифае это «гибкие трансформации», конфигурация бандлов, хардкодинг динамических модулей и прочий тюнинг.
            — В браузере нет ФС — зачем использовать ../../models/user? Хотя можно использовать вот так models/user или userМodel при том, что такое именование можно задать одной строчкой сразу для сотни модулей.
            • 0
              > Веб приложения(SPA) — нет

              Почему? Только по тем 2-м причинам, что вы обозначили в статье?

              У вас в статье написано, что use case для использования browserify — «адаптация среды Node.js для работы в браузере». Можете расписать подробнее, что вы имеете ввиду?
              • +1
                Когда есть модуль, который был изначально написан под ноду и очень хочется его запустить в браузере для демонстрации его. Единственное, что останавливало это разные способы ввода-вывода и браузерифай это место отлично чинил. Или же есть проект под любую среду, но разделенный на CommonJS модули браузерифай отлично собирал эти модули для отправки на клиент.

                browserify main.js > bundle.js и готово — это было прекрасно.

                Потом эта идея обросла хотелками от сообщества и браузерифай превратился в комбаин по натягиванию окружения node.js на реальность в браузере. В этот момент я сбежал от него.
                • 0
                  Итак, ваше мнение, в контексте данной статьи, что лучше всего подойдет для «изоморфного JS кода»? LMD, browserify или это больше дело вкуса и предпочтений (как вы говорите "кому как нравится конфигурировать сборку декларативно или императивно")?
                  • 0
                    Изоморфность оч скользкая штука. Например если ее рассматривать ее в контексте реиспользования кода, то как правило таких случаев очень мало или нужно писать абстрактный код (как написано в статье). Чаще все-таки есть сторона АПИ, прокся (для агрегации АПИ) и фронтэнд. Если проект достаточно большой, то 3 эти части могут писать разные группы и под разные среды. Например Ruby + Node.js + DOM (как написано в статье Закаса). И тогда пересечений в общей базе кода у них должно быть по минимуму во избежания конфликтов или каскада наследований в абстрактных частях.

                    Остается изоморфность модулей те методы запуска CommonJS в браузере. Тут способов более чем 3. Ну и спрашивать меня что лучше не совсем корректно :)
              • 0
                Забыл еще важный момент. Тк конфиги LMD декларативны, то возможно делать миксины и наследование конфигов, например прозрачно подменять локаль миксином или наследовать от абстрактной сборки. Еще есть мелочи вроде изоляции модуля, когда тот не может делать require() и алиасы (симлинки) для модулей.
            • 0
              browserify.
              require('someModule/maybe/mappedToFS', {expose: 'shortNameOfModuleAndItCanBeDoneInBuildFile'}), там где надо
              там где надо указываете basedir и все, он будет рутом и можно будет писать/по/неймспейсам при этом это будет проще дебажить потому что понятно что где лежит сразу, и в принципе раскладывание по неймспейсам по папкам это общепринятая практика в разных языках.
              можно указать entry point (и даже не один) у которого указать basedir и он будет автоматом на все распространен. в общем никаких проблем не вижу и не понимаю, в моем случае у меня есть бандлы, все приложение рисуется на сервере И на клиенте, бандлы собираются автоматически синхронные и асинхронные версии, все просто до безумия и я не вижу никаких проблем вызванных браузерифаем у себя.

              ../… вот такие пути нельзя использовать, это да, безумие. нет, я имею в виду вообще, такие пути вообще нельзя использовать нигде, особенно в браузере, но вообще — в любом коде. это всегда приводит к проблемам. разве что можно ./ для указания принадлежности к текущему неймспейсу.
              • 0
                Вы делаете полный ремап всех модулей или одни модули относительные, а другие по expose?
                • 0
                  в одном проекте модули которые по неймспесам разбиты и идут components/component от basedir, по expose загружаю модули из node_modules И bower_components (debowerify не всегда нормально отрабатывает, поправить его не успел еще) и прочих вендорных скриптов.
                  в другом джаваскрипт и цссы вообще собираются в зависимости по html шаблонам, и подгружаются и инициализируются автоматически, в этом случае происходит полный ремапинг — но он автоматический, не вручную прописываю конечно же.
                  в первом случае browserify именно как сборщик по зависимостям работает, во втором — как удобный манипулятор js для того что бы например исключить одинаковые вещи которые есть в основном js из js для конкретной страницы \ асинхронного загруженного компонента (например и там и там прописана зависимость от hogan.js — автоматом исключаю общее (на самом деле там несколько хитрее, и в большинстве случаев грузится только то что реально есть (может находится) на странице.
                  • +1
                    Можно посмотреть код конфига сборки?
                    • 0
                      ответил в личку
  • –5
    ебаный жабаскрипт пророс на сервер. удачного дебага коллбека на коллбеках
    • 0
      Ньюфаги не могут в Q.
      • 0
        а правильные люди используют async
  • 0
    Из озвученных трех проблем ныне существующего разделения клиент/сервер действительно ощущаю только одну: проблема взаимодействия с поисковиками. Сдается мне, что в качественном индексе заинтересованы и поисковики, так что время играет на нас. В такой перспективе получается, что вовсе не обязательно все движется в сторону изоморфного javascript, как вы его назвали.
  • 0
    Изоморфный — это как у 1С? Вроде восьмая платформа давно вышла.
    • 0
      У 1С не изоморфный. Их веб-клиент генерит html на клиенте. Им нафиг не нужно SEO, совсем другая специфика.
      • 0
        Имел ввиду что 1С код можно с помощью директив выполнять и на клиенте, и на сервере.
        • 0
          Ну там &НаКлиентеНаСервере используется дико редко. Гляньте код любой типовой конфигурации. Только для сильно вспомогательных функций. Это вообще не то.
          • 0
            1С-ников на хабре мало, вряд ли кто-то разъяснит. Но насколько я знаю, с выходом тонкого клиента (не вебклиента), эти директивы стали активно юзаться.

            Просто слова про «первый, единственный» и т.д. немного некорректны.
            И, кстати, 1С код использовался именно для логики приложений (конфигурации). Также как JavaScript для HTML.
            По мне, так аналогия полная.
            • +1
              Уверяю вас, на счет сходства вы ошибаетесь (есть и 1С в моем темном прошлом)
              • 0
                А, тогда благодарю, что разжевали. Одним заблуждением стало меньше.
            • 0
              Попробую разъяснить. У 1С-предприятия есть 2 способа построения форм и интерфейсов. 8.0 и 8.1 — обычные формы (обычное приложение), в 8.2 добавились еще управляемые формы (управляемое приложение). В обычных формах разработчик размещает элементы попиксельно с привязкой к определенным границам. В управляемых формах элементы размещаются декларативно, что-то вроде здесь будет такая-то кнопка, за ней следует такое-то поле, ниже еще кнопка, здесь группируем, здесь еще что-нибудь выскакивает и т.д.
              v8.1c.ru/beta_ma/ma_forms.htm

              Старые конфигурации использовали преимущественно обычные формы (управление торговлей 10.3, бухгалтерия предприятия 1.6, 2.0, ЗУП 2.5 и т.д.). В них не требуется указания директив &НаКлиенте, &НаСервере, да и по сути нет тонкого клиента.

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

              Скорее всего zag2art, с 1С завязал уже давно
              • 0
                А вы прочтите мой комментарий внимательней, изоморфным (который может испольняться и на сервере и на клиенте) в 1С можно считать лишь код, работающий в управляемом приложении в режиме &НаКлиентеНаСервере, а он используется лишь для дико вспомогательных вещей.

                Аналогия с 1С была бы, если бы в 1С можно было все приложение полностью запускать и на клиенте и на сервере (весь абсолютно код, включая доступ к данным и т.д.)
                • 0
                  Если бы 1С удалось реализовать управляемые формы, в которых вообще не нужно было бы указывать &НаКлиенте, &НаСервере и т.д., и можно было бы вызывать полноценное API из них (запросы, использовать все типы), тогда 1с-ые управляемые формы можно было бы назвать «изоморфными». То есть не смотря на окружение (толстый клиент, тонкий клиент, веб-клиент) они бы работали одинаково…
  • +2
    Хорошая статья. Отлично расписаны преимущества, которые даёт использование full-stack фреймворков.
    Странно, что ничего не сказано про Derby.js, который на мой взгляд лучше тех примеров full-stack фреймворков, которые привёл автор.

    Соединив Express, Handlebars, Director и Browserify, мы получим генерацию html на клиенте и сервере, а также повторное использование кода и модулей. Это здорово, конечно. Но нам бы еще динамически связать наши данные с html. А в идеале синхронизировать данные клиентов между собой. Решить эти проблемы можно отдельными взаимозаменяемыми модулями, но вы потеряете в красоте api. Другая крайность — получить монолитный, негибкий фреймворк, на подобие Meteor. В Derby все эти проблемы решены самым элегантным образом. Найдена золотая середина между гибкостью и удобностью. Сложно придумать — как сделать лучше. Не надо изобретить велосипед, ездите на Derby.
    • +1
      Я тоже удивился, что Derby не упоминается, ИМХО из известного мне он больше всего подходит под описанную архитектуру.
  • +1
    Nicholas C. Zakas отлично описал⇗ то, как по его мнению...

    Перевод
  • 0
    "Картинка из статьи для привлечения внимания" — Улыбнуло =)
    Юмористическая откровенность =)

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