xvEngine - Framework FrontEndowo-Backendowy

1

Witam.
Tym razem chciałbym pokazać, pochwalić się własnym tworem, do obsługi frontendu z poziomu PHP ;)

Demo:
http://www.tattool.co/xplore/

Więcej źródeł przykładów:
https://github.com/bordeux/xvEngine/

<font size="5"> Z czym się to je </span>

Framework bazuje na 3 istotach

  • komponenty
  • serwisy
  • handlery

<font size="5"> Komponenty </span>
Komponent to jest widok, każdy komponent posiada 3 pliki, np.

  • ButtonComponent.js - klasa w JavaScripcie, która zawiera metody i opcje przycisku
  • ButtonComponent.scss - ostylowanie
  • ButtonComponent.php - interfejs dla PHP, który pośrednio odwozruje metody z klasy JavaScriptiowej

Komponent jest tutaj właśnie czymś w postaći przycisku, specyfinczego inputu (np colorInput, imageInput itp), czy też okna modalnego.

<font size="5"> Serwisy </span>
Są to klasy, które działają nie zależnie od widoku, działają w tle, w każdym momencie można do nich się odwołać. Np. serwis do ustawiania metatagów
application.services.utils.metaTags.add("meta-key", "meta-value");

czy też do pokazania progressu wczytywania strony
application.services.ui.progress.show();

<font size="5"> Handlery </span>
Elementy, które scalają logiczną część aplikacji. Podstawowe to:

  • ActionHandler(string $idKomponentu) - pobiera referencje do jakiegoś komponentu, który już istnieje, aby wykonywać na nim metody.
  • RequestHandler(string $url) - wykonuje request do danej strony. Wynikiem tego requestu jest kolejna paczka Handlerów.
  • ServiceHandler(string $nameSpaceSerwisu) - pobiera referencje do serwisu, aby wykonywac na nim metody
  • PageHandler(AbstractComponent $component) - ustawia główny komponent do strony, czyli ustawia go w body, usuwajac poprzedni.
  • HistoryHandler(string $url) - ustawia adres URL w przeglądarce poprzez history API w HTML5

<font size="5"> Przykład w praktyce </span>
Mamy na celu stworzyć przycisk. Po naciśnięciu na niego, ma się zmienić tekst przycisku na "Loading...", następnie zrobić request do serwera, w celu pobrania informacji.

Tak więc najpierw musimy stworzyć stronę z przyciskiem:

<?php
//...
/**
* @Route("/przycisk/")
*/
public function indexAction(){
	
	$this->response->addHandler(function(){
		$page = new PageHandler($this->getView());
		$page->setPageName("przycisk")
		return $page;
	}, $this);
	
	return $this->response;
}

public function getView(){
	$view = new ButtonComponent("button1");
	$view->setText("Nacisnij mnie!");
	
	$view->on("onClick", function() use($view){//event gdy uzytkownik nacisnie guzik
		$action = new ActionHandler($view->getId()); //pobieramy referencje do klasy przycisku
		$action->setText("Loading..."); //zmieniamy label przycisku
		$action->off("onClick"); //odbindujemy akcje na przycisku, by uzytkownik nie kliknal 2x
		return $action;
	});
	
	$view->on("onClick", function() use($view){
		$request = new RequestHandler("/przycisk/dalej/"); //wykonujemy request do podanej strony
		$request->setOption("progress", true); //zarazem ma sie pokazac progress
		$requet->addPost("aktualnyLabel", CustomParam::Get($view->getId())->getText()); //w poscie doslemy sobie aktualny label przycisku
		return $request;
	});
	return $view;
}
//...
?>

W ten sposób utworzyliśmy przycisk. Teraz zróbmy odpowiedź serwera :)

<?php
//...
/**
* @Route("/przycisk/dalej/")
*/
public function indexAction(){
	
	$this->response->addHandler(function(){
		$action = new ActionHandler("button1");
		$action->setText("Dziękuje!"); //zmieniam po requescie label przycisku 
		return $action;
	}, $this);
	
	return $this->response;
}
//...
?>

<font size="5"> Zalety </span>

  • Jakość kodu JS jest bardzo wysoka. Każdy komponent ma swoj namespace wykonany na podstawie struktury katalogu. Wszystko napisane obiektowo, że nie ma nigdzie funkcji globalnych itp
  • Każdy element ma swoje miejsce, i jest odizolowane od reszty. Handlery łączą elementy, w postaci serwis z komponentem, komponent z serwisem itp
  • Można stworzyć cały portal bez przeładowywania strony. Wszystko na ajaxie, z obsługą histori przeglądarki itp.
  • Nie spotkałem się jeszcze z efektem wąskiego gardła. Czasami jest ciężka logika jakiegoś zdarzenia, dlatego też takie cięzkie elementy można napisać w czystym JSie (dirty workaround'y) w postaci serwisu, i odwolywac sie do tego sewisu z poziomu komponentu.
  • Lubie placki
  • Po napisaniu wszystkich komponentów, które na stronie wysępują, mało kiedy wchodzę w część JS'ową. Zajmuje się tym co kocham - programowaniem, niż wkurzaniem się JavaScriptem :)

<font size="5"> Wtf, nie lepiej pisać w czystym htmlu? </span>
Pisząc standardowo, w htmlu i jquery można dojść, że portal staje sie bardziej skomplikowany. Powstają niezliczone ilości JavaScriptu , przez co ciężko się połapać. Szczególnie gdy jest rotacja pracowników, gdzie nowy pracownik nie zna wszystkich eventow na stronie.

Rozwiązanie co przedstawiam narzuca pewne rygory i pojmanie logiki frameworka. Trzeba tylko wiedzieć że wszystko jest obiektem, i wywołujesz na tych obiektach metody. Wraz z wzrostem portalu, nie zmienia się trudność kodu :)

<font size="5"> AngularJS jest, ReactJS, po co to pisałeś? </span>
A bo kiedy zaczynałem, Angular to była nowość, a ReactJS nawet w głowach nie było :)

Czekam na opinie, komentarze, jaki kolwiek feedback :)

0

Żresz baterię niepotrzebnym js-em urządzeniom mobilnym, no i powodzenia bez JS-u. Nie lubię takich wynalazków.

0

Rozumiem, dla niektórych GUI to zbędna rzecz :) A tak na serio, to ja byłem za tym by zrobić osobną wersje na mobilne, ale ja tu tylko programuje, design i UI nie ja robiłem. Tak więc musiałem zrobić narzędzie, które podoła wyzwaniu, i będzie dość szybkie na komórki.

Bo pisząc do w Angularze (poprzednia ekipa to robiłą), no efekt nie był zdumiewający :>

NonJavaScript - takich użytkowników jest mało, i ten 0.1% nie zrobi różnicy.
Natomiast google dostaje już prerenderowaną stronę. Na serwerze mam zainstalowany PhantomJS co parsuje i wysyła raw HTML do googlebota ;)

0

Konstruktywny feedback, świat poszedł do przodu i dzisiaj mamy websockety i event sourcing, twój pomysł może i działa ale można to zrealizować prosciej, szybciej i mniejszą ilością kodu. Brakuje komunikacji w czasie rzeczywistym i asynchroniczności.

0

Przerobić to na sockety żaden problem. Tylko problemem jest język backendowy. Był narzucony PHP, tak więc musiałem się ograniczyć do ajaxa ;) Chciałem to zrobić na ReactPHP, ale to nie pewne było. I dlatego pozostałem na symfonii.

Na socketach lepiej by to działało :) Tylko trzeba zmienić requestHandler (1 klasę w JS) i wtedy mamy websockety.

Asynchroniczność - też daje radę. Obecnie jest tak że wszystkie handlery są wykonywane w kolejce, za pomocą Q.js. Poprzez ustawienie w handlerze atrybutu "Async" jest wykonywany asynchronicznie :)

0

Jedno 'ale', przerzuciłeś warstwe prezentacji na backend, a od takich rozwiązań się odchodzi zwłaszcza produkcyjnie bo wymuszasz komunikacje z serwerem (thin client, fat server), a to aż prosi się o problemy z wydajnością i skalowaniem. Sama strona ładuje się ponad 1s, to bardzo mierny wynik i nawet jeżeli zastosujesz cache to narzut pehapa będzie tu bardzo duży. Technologia, którą proponujesz nie wspiera rozwiązań multi screen - przykładowo, chce mieć frontend na Web, Mobile oraz apki natywne. Na oko, w tym przypadku musiałbym zbudować conajmniej dwa jak nie trzy systemy webowe, żeby to zrealizować.

Świat nie kończy się na pehapie i czasem zerknij co ciekawego oferują inne technologie :)

0

zwłaszcza produkcyjnie bo wymuszasz komunikacje z serwerem

Właśnie że nie. Nie muszę się w ogóle komunikować z serwerem. Komunikuje się w momencie gdy potrzebuje coś zapisać lub pobrać dane. Wejdź np. w Toola. Tam wszystko jest po stronie przeglądarki, 0 Requesta do serwera, prócz requestów do statycznych rzeczy (assetów) :)

To nie jest tak że po każdym kliku leci request do serwera :) Request leci w momencie kiedy użyjesz RequestHandler. Tak to działa wszystko offline.

Offline do tego stopnia, że jest już napisana na tym aplikacja na PhoneGap ;>

1

Tak na szybko to przejrzałem i jedyne co mi rzuciło się w oczy, to masz XV\Bundle\EngineBundle\Classes. To 'classes' to wg mnie bez sensu :) nic nie mówi o tym co jest w środku.

1 użytkowników online, w tym zalogowanych: 0, gości: 1