Node.js jako middle-end



Jedną z najbardziej interesujących zalet jakie wnosi idea SSJS jest możliwość wykorzystania tego samego kodu zarówno po stronie przeglądarki jak i po stronie serwera. Daje to możliwość współdzielenia części logiki, modelu, walidatorów, czy warstwy widoku. Najprościej przedstawia się sytuacja kiedy od razu napiszemy cały backend w JavaScriptcie, jednak w praktyce częściej będziemy integrować Node.js, czy inne rozwiązanie SSJS, z już istniejącą aplikacją.



Taką warstwę, znajdującą się pomiędzy backendem i frontendem, z zachowaniem pełnej logiki rozumowania, nazywamy middle-endem (po więcej informacji odsyłamy do twórcy tej koncepcji http://blog.getify.com/2010/07/what-exactly-is-the-middle-end/). Zwróćmy też uwagę by nie mylić middle-endu z middlewarem. Zbadaliśmy możliwość zastosowania Node.js jako proxy służące jako silnik szablonów, choć oczywiście możliwa jest też inna architektura. W nowoczesnych aplikacjach webowych zdarza się, że niemal cała struktura drzewa DOM tworzona jest przez JavaScript po stronie przeglądarki. Niestety nie jest to przyjazne rozwiązanie dla systemów o słabszej wydajności (IE lub przeglądarki mobilne). Z pomocą przychodzi właśnie JavaScriptowy serwer proxy.

Idea była następująca: nasze middle-endowe proxy wstawiliśmy pomiędzy już działający backend (napisany w dowolnym języku), a przeglądarkę użytkownika. Proxy przyjmowało zapytania od użytkownika i przekazywało je dalej do serwera z aplikacją backendową. Backend zwracał JSON z danymi (modelem) dla tej podstrony, template’ami i dodatkowymi informacjami jak na przykład listą skryptów JavaScript do załadowania. JavaScriptowe proxy podejmowało następnie decyzję czy klient dysponuje odpowiednią przeglądarką i:

  • jeśli tak, to wysyłało krótki, podstawowy szablon wraz z dołączonymi skryptami, szablonami oraz modelem tak by przeglądarka sama stworzyła stronę,
  • jeśli nie, wykorzystując serwerową implementację DOM-a, uruchamiało standardowe skrypty, które w pierwszym rozwiązaniu zostały wysłane do przeglądarki i tworzyło pełne drzewo DOM.

Schemat działania naszej aplikacji middle-end.

Efekt końcowy działania w obydwu przypadkach był identyczny. Wolniejsza przeglądarka otrzymywała gotowy HTML, aby odciążyć ją od prac z JavaScript. Chociaż graf powyżej jako przykład podaje IE6, bardziej interesującym zastosowaniem byłoby generowanie HTML-a po stronie serwera dla urządzeń mobilnych, które są stosunkowo słabe, bądź w ogóle nie posiadają wsparcia dla JavaScriptu. Przykładem, mogłoby być generowanie dynamicznego mashup-u typu Pageflakes / Netvibes.

Udało nam się użyć po stronie serwera jQuery (wyłączyliśmy animacje) i przypuszczamy, że większość popularnych bibliotek nie będzie miała problemów z działaniem. Potwierdza to przykład YUI, które w dużej części działa już bez problemów na Node.js.

    var query = url.parse(req.url).query;
    httpget('localhost', '/', 8888, function(data) {
        __model.data = JSON.parse(data);
        res.writeHead(200, { 'Content-Type': 'text/html' }); 
        
        if (query === "fallback" ) {
            jsdom.env({
                html: templateHtml.replace('{{scripts}}', ''),
                scripts: __scripts.map(function(el){
                  return el.indexOf("http") === 0 ? el : __staticPath + el;
                }),
                done: function(errors, window) {
                    errors && console.log(errors);
                    
                    var __doc = window.document;
                    
                    window.jQuery.fx.off = true;
                    window.init(__model); //?
                    
                    var scripts = __doc.getElementsByTagName('script');
                    var scriptArr = Array.prototype.slice.call(scripts);
                    
                    for(var i = 0; i < scriptArr.length; i++) {
                        var s = scriptArr[i];
                        s.parentNode.removeChild(s);
                    }
                    
                    res.write(window.document.doctype.toString());
                    res.write(window.document.innerHTML);
                    res.end();
                }
            });
        } else {
            var dynamicScripts = __scripts.map(function(el) {
              return '';
            })
            
            dynamicScripts.push('');   
            
            res.end(templateHtml.replace('{{scripts}}', 
                dynamicScripts.join('')));
        }
    });
  

Fragment implementacji generowania dokumentu po stronie serwera (server.js). Pełny kod

Pewną trudnością jest natomiast pisanie kodu, który byłby przenośny pomiędzy środowiskiem przeglądarki i serwerowym oraz samo emulowanie przeglądarki po stronie serwera. Aby to lepiej zbadać zajęliśmy się stworzeniem walidatora, który był odpowiedzialny za walidację danych formularza po stronie klienta i serwera. Tutaj głównym pytaniem było w jakiś sposób strukturalizować kod, aby można go było swobodnie wywoływać po stronie przeglądarki i Node.js.



Z pewnością ciekawym wzorcem jest opakowywanie kodu w podobne wywołania jakimi posługuje się Node przy dołączaniu modułów. Z wywoływaniem skryptów w kontekście podobnym do przeglądarkowego jednak już tak prosto nie jest, ponieważ node’owa metoda vm.runInNewContext() zachowuje się w sposób dość nieoczekiwany i wymaga trochę hackowania. Na pewno w tym temacie jest jeszcze sporo do dopracowania.

W warstwie proxy wykorzystaliśmy moduł jsdom, który umożliwił dynamiczne budowanie DOMa, zarówno z poziomu API (appendChild, createElement etc.) jak i poprzez “nakładkę” w postaci jQuery.

Więcej informacji:

Reinmar,
Piotrek Koszuliński
@reinmarpl
http://code42.pl

@gustaff_weldon

Bartek Szopka
@bartaz

Komentarze


1

Bobby napisał/a 28.09.2011 o 10:11

All of my quesotins settled-thanks!

2

occgnunfq napisał/a 29.09.2011 o 16:38

Yol0Jz tnpljnprcnuu

3

vwhpaa napisał/a 30.09.2011 o 14:37

MZ8qE5 , [url=http://qmofkexietbz.com/]qmofkexietbz[/url], [link=http://vfynqdtgsdiw.com/]vfynqdtgsdiw[/link], http://rcyufxkjnpoo.com/

Dodaj komentarz


Zapraszamy na DevMeetings

Wydajność NodeJS kontra reszta świata

Poznań 03.09.2011

noSQL - naturalny storage aplikacji JS

Warszawa 10.09.2011

Middle-End w oparciu o ServerSide JS

Kraków 24.09.2011
Copyright © DevCamp 2011