Aurelia vs. Angular 2 — porównanie kodu

Opublikowany: 2022-03-11

Angular i Aurelia, potomkowie starego dobrego JavaScript Angular 1, są zaciekłymi konkurentami, opracowanymi i wydanymi mniej więcej w tym samym czasie iz podobną filozofią, ale różniącymi się pod wieloma kluczowymi względami. W tym artykule przeprowadzimy równoległe porównania tych różnic w funkcjach i kodzie.

Krótko mówiąc, Aurelia została stworzona przez Roba Eisenberga, znanego jako twórca Durandala i Caliburna. Pracował w zespole Angular 2 w Google, ale odszedł w 2014 roku, kiedy jego poglądy na temat tego, jak powinien wyglądać nowoczesny framework, różniły się od ich.

Podobieństwa utrzymują się również na bardziej technicznym poziomie: szablony i powiązane z nimi komponenty (lub elementy niestandardowe) są rdzeniem zarówno aplikacji Angular, jak i Aurelia i obie wymagają posiadania komponentu głównego (tj. aplikacji). Co więcej, zarówno Angular, jak i Aurelia intensywnie używają dekoratorów do konfiguracji komponentów. Każdy komponent ma ustalony cykl życia, do którego możemy się podłączyć.

Jaka jest więc różnica między Aurelia a Angular 2?

Według Roba Eisenberga kluczowa różnica tkwi w kodzie: Aurelia jest dyskretna. Tworząc aplikację Aurelia (po konfiguracji), piszesz w ES6 lub TypeScript, a szablony wyglądają jak absolutnie rozsądny HTML, zwłaszcza w porównaniu z Angularem. Aurelia to konwencja ponad konfiguracją i w 95% przypadków będziesz w porządku, używając domyślnych konwencji (takich jak nazewnictwo szablonów, nazewnictwo elementów itp.), podczas gdy Angular wymaga, abyś dostarczył konfigurację praktycznie do wszystkiego.

Aurelia jest również uważana za bardziej zgodną ze standardami, choćby dlatego, że nie rozróżnia wielkości liter w tagach HTML, podczas gdy Angular 2 jest. Oznacza to, że Angular 2 nie może polegać na parserze HTML przeglądarki, więc stworzył własny.

Innym czynnikiem, który należy wziąć pod uwagę przy wyborze między ramami SPA, jest społeczność – ekosystem – wokół nich. Zarówno Angular, jak i Aurelia mają wszystkie podstawy (router, silnik szablonów, walidacja itp.) i łatwo jest uzyskać natywny modalny lub użyć jakiejś biblioteki innej firmy, ale nie jest niespodzianką, że Angular ma większą społeczność i większy rozwój zespół.

Co więcej, chociaż oba frameworki są open source, Angular jest głównie rozwijany przez Google i nie jest przeznaczony do komercjalizacji, podczas gdy Durandal, Inc., który zatrudnia główny zespół, podąża za modelem monetyzacji Ember.js poprzez doradztwo i szkolenia.

Aurelia vs. Angular: porównanie kodu

Przyjrzyjmy się niektórym z najbardziej godnych uwagi funkcji, które podkreślają filozofię stojącą za każdym frameworkiem.

Po sklonowaniu projektów seedów dla Angulara i Aurelia, mamy aplikację ES6 Aurelia (możesz użyć Jspm/System.js, Webpack i RequireJS w połączeniu z ES6 lub TypeScript) oraz aplikację TypeScript Angular (WebPack).

Zaczynajmy.

Wiązanie danych

Zanim porównamy działające obok siebie przykłady, musimy przyjrzeć się pewnym różnicom składniowym między Aurelia i Angular 2, a mianowicie w kluczowej funkcjonalności wiązania wartości z kontrolera do widoku. Angular 1 używał do wszystkiego „brudnego sprawdzania”, metody, która skanowała zakres zmian. To, co zrozumiałe, spowodowało szereg problemów z wydajnością. Ani Angular 2, ani Aurelia nie poszli tą ścieżką. Zamiast tego używają wiązania zdarzeń.

Wiązanie danych w Angular 2

W Angularze łączysz dane za pomocą nawiasów kwadratowych i używasz nawiasów do wiązania zdarzeń, na przykład:

 <element [property]="value"></a> <element (someEvent)="eventHandler($event)"></a>

Wiązanie dwukierunkowe — gdy chcesz, aby zmiany w danych aplikacji odzwierciedlały widok i odwrotnie — jest kombinacją nawiasów kwadratowych i nawiasów. Tak więc w przypadku dwukierunkowych danych wejściowych działałoby to dobrze:

 <input type="text" [(ngModel)]="text"> {{text}}

Innymi słowy, nawiasy reprezentują zdarzenie, podczas gdy nawiasy kwadratowe reprezentują wartość przekazywaną do wejścia.

Zespół Angulara wykonał świetną robotę oddzielając wiążące kierunki: do DOM, od DOM i dwukierunkowe. Jest też dużo cukierków składniowych związanych z wiązaniem klas i stylów. Rozważmy na przykład następujący fragment kodu jako przykład jednokierunkowego wiązania:

 <div [class.red-container]="isRed"></div> <div [style.width.px]="elementWidth"></div>

Ale co, jeśli chcemy powiązać dwukierunkowe dane w komponent? Rozważ następującą podstawową konfigurację wprowadzania:

 <!-- parent component --> <input type="text" [(ngModel)]="text"> {{ text }} <my-component [(text)]="text"></my-component> import {Component, Input} from '@angular/core'; @Component(/* ... */) export class MyComponent { @Input() text : string; } <!-- child component --> <input [(ngModel)]="text"> Text in child: {{ text }}

Zauważ, że aby użyć ngModel , twój moduł musi zaimportować FormsModule z @angular/forms . Teraz mamy coś ciekawego. Aktualizacja wartości w danych wejściowych nadrzędnych zmienia wartości wszędzie, ale modyfikowanie danych wejściowych dziecka wpływa tylko na to dziecko. Jeśli chcemy, aby aktualizował wartość rodzica, potrzebujemy zdarzenia informującego rodzica. Konwencja nazewnictwa dla tego zdarzenia to property name + 'Change' , na przykład:

 import {Component, Input, Output, EventEmitter} from '@angular/core'; @Component(/* ... */) export class MyComponent { @Input() text : string; @Output() textChange = new EventEmitter(); triggerUpdate() { this.textChange.emit(this.text); } }

Wiązanie dwukierunkowe zaczyna działać poprawnie zaraz po powiązaniu ze zdarzeniem ngModelChange :

 <!-- child component --> <input [(ngModel)]="text" (ngModelChange)="triggerUpdate($event)">

A co z jednorazowym wiązaniem, gdy skutecznie mówisz frameworkowi, aby ignorował powiązane wartości, nawet jeśli się zmienią?

W Angular 1 użyliśmy {{::value}} do jednorazowego powiązania. W Angular 2 jednorazowe wiązanie się komplikuje: dokumentacja mówi, że możesz użyć changeDetection: ChangeDetectionStrategy.OnPush w konfiguracji komponentu, ale to spowoduje, że wszystkie twoje wiązania będą jednorazowe.

Wiązanie danych: Droga Aurelia

W przeciwieństwie do Angulara 2 powiązanie danych i zdarzeń w Aurelia jest naprawdę proste. Możesz użyć interpolacji, tak jak w Angular's property="${value}" lub użyć jednego z następujących typów wiązania:

 property.one-time="value" property.one-way="value" property.two-way="value"

Nazwy nie wymagają wyjaśnień. Ponadto istnieje property.bind="value" , ​​która jest cukrem składniowym, który samoczynnie wykrywa, czy powiązanie powinno być jednokierunkowe, czy dwukierunkowe. Rozważać:

 <!-- parent--> <template bindable="text"> <input type="text" value.bind="text"/> <child text.two-way="text"></child> </template> <!-- child custom element --> <template bindable="text"> <input type="text" value.bind="text"/> </template>

W powyższym fragmencie można konfigurować zarówno @bindable , jak i @Input , dzięki czemu można łatwo zmienić takie rzeczy, jak nazwa powiązanej właściwości itp.

A co z wydarzeniami? Aby powiązać ze zdarzeniami w Aurelia, używasz .trigger i .delegate . Na przykład, aby komponent podrzędny uruchamiał zdarzenie, możesz wykonać następujące czynności:

 // child.js this.element.dispatchEvent(new CustomEvent('change', { detail: someDetails }));

Następnie posłuchaj tego u rodzica:

 <child change.trigger="myChangeHandler($event)"></child> <!-- or --> <child change.delegate="myChangeHandler($event)"></child>

Różnica między tymi dwoma polega na tym, że .trigger tworzy procedurę obsługi zdarzeń na tym konkretnym elemencie, podczas gdy .delegate dodaje detektor na document . Oszczędza to zasoby, ale oczywiście nie będzie działać w przypadku zdarzeń niebulgoczących.

Podstawowy przykład Aurelia kontra Angular

Teraz, gdy omówiliśmy wiązanie, stwórzmy podstawowy komponent, który renderuje skalowalną grafikę wektorową (SVG). Będzie super, dlatego nazwiemy to awesome-svg . To ćwiczenie zilustruje zarówno podstawową funkcjonalność, jak i filozofię Aurelia i Angular 2. Przykłady kodu Aurelia z tego artykułu są dostępne w serwisie GitHub.

Przykład prostokątów SVG w Aurelii

Najpierw utwórzmy plik JavaScript:

 // awesome-svg.js import {bindable} from 'aurelia-framework'; export class AwesomeSvgCustomElement { @bindable title; @bindable colors = []; }

Teraz przejdźmy do kodu HTML.

W Aurelia możesz określić szablon (lub użyć wbudowanego) z adnotacjami @template , @inlineView lub nawet @noView , ale po wyjęciu z pudełka wyszukuje plik .html o tej samej nazwie co .js plik. To samo dotyczy nazwy elementu niestandardowego — możesz ustawić ją za pomocą @customElement('awesome-svg') , ale jeśli tego nie zrobisz, Aurelia skonwertuje tytuł do postaci myślników i poszuka dopasowania.

Ponieważ nie określiliśmy inaczej, element będzie nazywał się awesome-svg , a Aurelia wyszuka szablon o tej samej nazwie co plik js (tj awesome-svg.html ) w tym samym katalogu:

 <!-- awesome-svg.html --> <template> <h1>${title}</h1> <svg> <rect repeat.for="color of colors" fill.bind="color" x.bind="$index * 100" y="0" width="50" height="50"></rect> </svg> </template>

Zwróć uwagę na tag <template> ? Wszystkie szablony muszą być umieszczone w tagu <template> . Warto również zauważyć, że używasz ` dla … of and the string interpolation ${title}` tak jak w ES6.

Teraz, aby użyć komponentu, powinniśmy albo zaimportować go do szablonu za pomocą <require from="path/to/awesome-svg"></require> lub, jeśli jest on używany w całej aplikacji, zglobalizować zasób w funkcji configure frameworka z aurelia.use.globalResources('path/to/awesome-svg'); , który raz na zawsze zaimportuje komponent awesome-svg .

[Uwaga, jeśli nie zrobisz żadnej z tych czynności, <awesome-svg></awesome-svg> będzie traktowany jak każdy inny tag HTML, bez błędów.]

Możesz wyświetlić komponent za pomocą:

 <awesome-svg colors.bind="['#ff0000', '#00ff00', '#0000ff']"></awesome-svg>

To renderuje zestaw 3 prostokątów:

Przykład prostokątów SVG w Aurelii

Przykład prostokątów SVG w Angular 2

Teraz zróbmy ten sam przykład w Angular 2, dostępnym również na GitHub. Angular 2 wymaga podania zarówno szablonu, jak i nazwy elementu:

 // awesome-svg.component.ts import {Component, Input} from '@angular/core'; @Component({ selector: 'awesome-svg', templateUrl: './awesome-svg.component.html' }) export class AwesomeSvgComponent { @Input() title : string; @Input() colors : string[] = [] }

Widok jest tam, gdzie sprawy trochę się komplikują. Po pierwsze, Angular po cichu traktuje nieznane tagi HTML w taki sam sposób, jak robi to przeglądarka: uruchamia błąd mówiący, że coś w stylu my-own-tag jest nieznanym elementem. Robi to samo dla wszystkich powiązanych właściwości, więc jeśli masz literówkę gdzieś w kodzie, przyciągnęłoby to dużą uwagę, ponieważ aplikacja uległaby awarii. Brzmi dobrze, prawda? Tak, ponieważ od razu zauważysz, że zepsujesz aplikację, a nie, ponieważ to po prostu zła forma.

Weź pod uwagę ten fragment, który jest idealny pod względem składni wiązania:

 <svg> <rect [fill]="color"></rect> </svg>

Mimo że czyta się dobrze, pojawi się błąd typu „nie można powiązać z „wypełnieniem”, ponieważ nie jest to znana właściwość „:svg:rect”.”. Aby to naprawić, musisz zamiast tego użyć składni [attr.fill]="color" . Zauważ również, że wymagane jest określenie przestrzeni nazw w elementach potomnych wewnątrz <svg/>: <svg:rect> , aby Angular wiedział, że nie powinno to być traktowane jako HTML. Rozwińmy nasz fragment:

 <!-- awesome-svg.component.html--> <h1>{{ title }}</h1> <svg> <rect *ngFor="let color of colors; let i = index" [attr.fill]="color" [attr.x]="i * 100" y="0" width="50" height="50" ></rect> </svg>

No to jedziemy. Następnie zaimportuj go w konfiguracji modułu:

 @NgModule({ declarations: [ AwesomeSvgComponent ] //... })

Teraz komponent może być używany w tym module, na przykład:

 <awesome-svg [colors]="['#ff0000', '#00ff00', '#0000ff']" title="Rectangles"></awesome-svg> 

Przykład prostokątów SVG w AngularJS 2

Elementy niestandardowe

Załóżmy teraz, że chcemy, aby nasz kod prostokąta był niestandardowym komponentem z własną logiką.

Elementy niestandardowe: Angular 2 Way

Ponieważ Angular 2 renderuje komponenty według tego, co pasuje do zdefiniowanego selektora, niezwykle łatwo jest zdefiniować niestandardowy komponent, na przykład:

 @Component({ selector: 'g[custom-rect]', ... })

Powyższy fragment kodu wyrenderowałby element niestandardowy do dowolnych tagów <g custom-rect></div> , co jest niezwykle przydatne.

Elementy niestandardowe: Droga Aurelii

Aurelia pozwala nam tworzyć niestandardowe elementy tylko z szablonu:

 <template bindable="colors, title"> <h1>${title}</h1> <svg> <rect repeat.for="color of colors" fill.bind="color" x.bind="$index * 100" y="0" width="50" height="50"></rect> </svg> </template>

Element niestandardowy zostanie nazwany zgodnie z nazwą pliku. Jedyna różnica w stosunku do nazewnictwa innych komponentów polega na tym, że podczas importowania, zarówno w konfiguracji, jak i za pomocą tagu <require> , należy umieścić .html na końcu. Na przykład: <require from="awesome-svg.html"></require> .

Aurelia ma również niestandardowe atrybuty, ale nie służą one temu samemu celowi, co w Angular 2. Na przykład w Aurelia możesz użyć adnotacji @containerless na niestandardowym elemencie rect . @containerless może być również używany z niestandardowymi szablonami bez kontrolera i <compose> , który zasadniczo renderuje rzeczy do DOM.

Rozważmy następujący kod zawierający adnotację @containerless :

 <svg> <custom-rect containerless></custom-rect> </svg>

Wynik nie zawierałby niestandardowego tagu elementu ( custom-rect ), ale zamiast tego otrzymujemy:

 <svg> <rect ...></rect> </svg>

Usługi

Jeśli chodzi o usługi, Aurelia i Angular są bardzo podobne, jak zobaczysz w poniższych przykładach. Załóżmy, że potrzebujemy NumberOperator , który zależy od NumberGenerator .

Usługi w Aurelii

Oto jak zdefiniować nasze dwie usługi w Aurelia:

 import {inject} from 'aurelia-framework'; import {NumberGenerator} from './number-generator' export class NumberGenerator { getNumber(){ return 42; } } @inject(NumberGenerator) export class NumberOperator { constructor(numberGenerator){ this.numberGenerator = numberGenerator; this.counter = 0; } getNumber(){ return this.numberGenerator.getNumber() + this.counter++; } }

Teraz dla komponentu wstrzykujemy w ten sam sposób:

 import {inject} from 'aurelia-framework'; import {NumberOperator} from './_services/number-operator'; @inject(NumberOperator) export class SomeCustomElement { constructor(numberOperator){ this.numberOperator = numberOperator; //this.numberOperator.getNumber(); } }

Jak widać, dzięki wstrzykiwaniu zależności dowolna klasa może być usługą w pełni rozszerzalną, dzięki czemu można nawet napisać własne przeliczniki.

Fabryki w Aurelii

Jeśli potrzebujesz fabryki lub nowej instancji ( Factory i NewInstance to tylko kilka popularnych resolwerów dostarczanych po wyjęciu z pudełka), możesz wykonać następujące czynności:

 import { Factory, NewInstance } from 'aurelia-framework'; @inject(SomeService) export class Stuff { constructor(someService, config){ this.someService = someService; } } @inject(Factory.of(Stuff), NewInstance.of(AnotherService)) export class SomethingUsingStuff { constructor(stuffFactory, anotherService){ this.stuff = stuffFactory(config); this.anotherServiceNewInstance = anotherService; } }

Usługi kątowe

Oto ten sam zestaw usług w Angular 2:

 import { Injectable } from '@angular/core'; import { NumberGenerator } from './number-generator'; @Injectable() export class NumberGenerator { getNumber(){ return 42; } } @Injectable() export class NumberOperator { counter : number = 0; constructor(@Inject(NumberGenerator) private numberGenerator) { } getNumber(){ return this.numberGenerator.getNumber() + this.counter++; } }

Adnotacja @Injectable jest wymagana, a aby faktycznie wstrzyknąć usługę, musisz określić usługę na liście dostawców w konfiguracji komponentu lub całej konfiguracji modułu, na przykład:

 @Component({ //... providers: [NumberOperator, NumberGenerator] })

Lub, co nie jest zalecane, można go również określić w bootstrap(AppComponent, [NumberGenerator, NumberOperator]) .

Pamiętaj, że musisz określić zarówno NumberOperator , jak i NumberGenerator , niezależnie od tego, jak je wstrzykniesz.

Wynikowy komponent będzie wyglądał mniej więcej tak:

 @Component({ //... providers: [NumberOperator, NumberGenerator], }) export class SomeComponent { constructor(@Inject(NumberOperator) public service){ //service.getNumber(); } }
Fabryki w Angular 2

W Angular 2 możesz tworzyć fabryki z adnotacją provide , która jest również używana do aliasowania usług w celu zapobiegania kolizjom nazw. Tworzenie fabryki może wyglądać następująco:

 let stuffFactory = (someService: SomeService) => { return new Stuff(someService); } @Component({ //... providers: [provide(Stuff, {useFactory: stuffFactory, deps: [SomeService]})] })

Transkluzja

Angular 1 miał możliwość dołączania treści, „slotu” z jednego szablonu do drugiego za pomocą transkluzji. Zobaczmy, co mają do zaoferowania jego potomkowie.

Projekcja treści z Angular 2

W Angular 2 transkluzja nazywa się „projekcją treści” i działa w ten sam sposób, co ng-transclude ; tzn. mówiąc w kategoriach Angulara 1, transkludowana treść korzysta z zakresu nadrzędnego. Dopasuje tag transkludowanej treści na podstawie selektora konfiguracji. Rozważać:

 @Component({ selector: 'child', template: `Transcluded: <ng-content></ng-content>` }) export class MyComponent {}

Następnie możesz użyć komponentu z <child-component>Hello from Translusion Component</child-component> , a otrzymamy dokładnie transkludowany kod HTML Yes wyrenderowany w komponencie potomnym.

W przypadku transkluzji wieloslotowej, Angular 2 ma selektory, których można używać w taki sam sposób, jak w przypadku konfiguracji @Component :

 <!-- child.component.html --> <h4>Slot 1:</h4> <ng-content select=".class-selector"></ng-content> <h4>Slot 2:</h4> <ng-content select="[attr-selector]"></ng-content>
 <!-- parent.component.html --> <child> <span class="class-selector">Hello from Translusion Component</span> <p class="class-selector">Hello from Translusion Component again</p> <span attr-selector>Hello from Translusion Component one more time</span> </child> 

Sloty w Angular2

Możesz użyć select w swoich tagach niestandardowych, ale pamiętaj, że tag musi być znany Angularowi 2.

Automaty z Aurelia

Pamiętasz, jak powiedziałem, że Aurelia stosuje standardy sieciowe, kiedy tylko jest to możliwe? W Aurelii transkluzja nazywana jest slotami i jest po prostu wypełniaczem dla Web Components Shadow DOM. Shadow DOM nie jest jeszcze stworzony dla automatów, ale jest zgodny ze specyfikacją W3C.

 <!-- child --> <template> Slot: <slot></slot> </template> <!-- parent --> <template> <child>${textValue}</child> </template>

Aurelia została zaprojektowana tak, aby była zgodna ze standardami, a Angular 2 nie. W rezultacie możemy robić więcej niesamowitych rzeczy z automatami Aurelii, na przykład używać zawartości zastępczej (próba użycia zawartości zastępczej w Angular 2 kończy się niepowodzeniem z <ng-content> element cannot have content ). Rozważać:

 <!-- child --> <template> Slot A: <slot name="slot-a"></slot> <br /> Slot B: <slot name="slot-b"></slot> Slot C: <slot name="slot-c">Fallback Content</slot> </template> <!-- parent --> <template> <child> <div slot="slot-a">A value</div> <div slot="slot-b">B value</div> </child> </template>

W taki sam sposób jak Angular 2, Aurelia wyrenderuje wszystkie wystąpienia slotu na podstawie dopasowania nazwy.

Automaty w Aurelii

Warto również zauważyć, że zarówno w Aurelia, jak i Angular, możesz kompilować części szablonu i renderować komponenty dynamicznie (używając <compose> z view-model w Aurelia lub ComponentResolver w Angular 2).

Cień DOM

Zarówno Aurelia, jak i Angular obsługują Shadow DOM.

W Aurelia użyj dekoratora @useShadowDOM i gotowe:

 import {useShadowDOM} from 'aurelia-framework'; @useShadowDOM() export class YetAnotherCustomElement {}

W Angularze to samo można zrobić z ViewEncapsulation.Native :

 import { Component, ViewEncapsulation } from '@angular/core'; @Component({ //... encapsulation: ViewEncapsulation.Native, }) export class YetAnotherComponent {}

Pamiętaj, aby sprawdzić, czy Twoja przeglądarka obsługuje Shadow DOM.

Renderowanie po stronie serwera

Jest rok 2017, a renderowanie po stronie serwera jest bardzo modne. Możesz już renderować Angular 2 na zapleczu za pomocą Angular Universal, a Aurelia będzie to mieć w 2017 roku, jak stwierdzono w postanowieniach noworocznych zespołu. W rzeczywistości w repozytorium Aurelii jest uruchomione demo.

Oprócz tego Aurelia od ponad roku ma możliwości progresywnego ulepszania, czego nie ma Angular 2 ze względu na niestandardową składnię HTML.

Rozmiar, wydajność i co dalej

Chociaż nie pokazuje nam całego obrazu, benchmarki DBMonster, z domyślnymi konfiguracjami i zoptymalizowaną implementacją, dają dobry obraz porównawczy: Aurelia i Angular pokazują podobne wyniki około 100 rerenderów na sekundę (testowane na MacBooku Pro), podczas gdy Angular 1 pokazał około połowy tego wyniku. Zarówno Aurelia, jak i Angular przewyższają Angular 1 około pięć razy, a oba są 40% przed Reactem. Ani Aurelia, ani Angular 2 nie mają implementacji Virtual DOM.

Jeśli chodzi o rozmiar, Angular jest mniej więcej dwa razy grubszy niż Aurelia, ale ludzie z Google nad tym pracują: plan działania Angulara obejmuje wydanie Angulara 4 z planami, aby był mniejszy i lżejszy, a jednocześnie poprawiał wrażenia programistów. Nie ma Angulara 3 i tak naprawdę numer wersji powinien zostać pominięty, gdy mówimy o Angularze, ponieważ główne wydania są planowane co 6 miesięcy. Jeśli spojrzysz na ścieżkę, którą obrał Angular od wersji alfa do obecnej wersji, zobaczysz, że nie zawsze była ona spójna z takimi rzeczami, jak zmiana nazw atrybutów z kompilacji na kompilację itp. Zespół Angulara obiecuje, że wprowadzanie zmian będzie łatwe migrować.

Od 2017 roku zespół Aurelia planuje wydać Aurelia UX, zapewnić więcej integracji i narzędzi oraz wdrożyć renderowanie po stronie serwera (co jest na mapie drogowej od bardzo dawna).

Angular 2 kontra Aurelia: kwestia gustu

Zarówno Angular, jak i Aurelia są dobre, a wybór jednego z nich to kwestia osobistego gustu i priorytetów. Jeśli potrzebujesz bardziej smukłego rozwiązania, Aurelia jest najlepszą opcją, ale jeśli potrzebujesz wsparcia społeczności, Angular jest Twoim zwycięzcą. To nie jest pytanie „Czy te ramy pozwalają mi…?” ponieważ odpowiedź brzmi po prostu „tak”. Zapewniają mniej więcej tę samą funkcjonalność, a jednocześnie podążają za różnymi filozofiami i stylami, a także z zupełnie innym podejściem do standardów internetowych.