Lately, conversations about JavaScript frameworks have been dominated by popular names like React (technically a library), Next.js, Svelte, Angular, and more.
These are all great tools, but have you heard of Aurelia 2?
When I first came across Aurelia, my reaction was, "What is that?" But after 2 years of working with it, I now believe it’s one of the best frameworks out there, if not the best.
Why do I think so?
Let me explain. I transitioned to Aurelia from React.js, and initially, I assumed it was just another JavaScript framework. However, as I delved deeper, I began to realize its true potential and power.
This article will serve as an introduction to Aurelia 2, where I’ll showcase some of its powerful concepts and why it stands out.
1. Event Aggregator
First up is the Event Aggregator, a concept you might be familiar with if you’ve worked in the C# ecosystem, but here’s how it works in Aurelia:
The Event Aggregator functions similarly to the event-based messaging patterns commonly used in C#. It’s a pub/sub system that allows you to publish and subscribe to custom events within your Aurelia applications.
This facilitates decoupled communication between different parts of your app. Just like in C#, where event aggregators or mediators are used to streamline event handling, Aurelia’s Event Aggregator is leveraged by the framework itself to publish events at various stages of the application's lifecycle and during specific actions.
import { IEventAggregator, resolve } from 'aurelia';
export class FirstComponent{
readonly ea: IEventAggregator = resolve(IEventAggregator);
bound() {
this.ea.publish('ea_channel', ‘PAYLOAD’)
}
}
import { IEventAggregator, resolve } from 'aurelia';
export class SecondComponent {
readonly ea: IEventAggregator = resolve(IEventAggregator);
bound() {
this.ea.subscribe('ea_channel', payload => {
// Do stuff inside of this callback
});
}
}
With this, we can effortlessly implement an event-driven architecture, addressing and resolving the coupling headaches often encountered with React and similar frameworks.
2. Dependency Injection
Dependency Injection (DI) is a design pattern that facilitates the creation of objects with their required dependencies, without the objects themselves being responsible for creating those dependencies. This promotes loose coupling between classes and their dependencies, enhancing modularity and testability.
Aurelia offers a powerful and flexible DI system that simplifies the process of wiring up different parts of your application. With Aurelia's DI, managing and injecting dependencies becomes seamless, resulting in cleaner, more maintainable code.
Additionally, this approach makes Test-Driven Development (TDD) easier, as it allows for straightforward mocking and testing of individual components without the need for complex setup or tightly coupled dependencies.
How it looks in practice:
import { IFileReader } from '@svc/file-reader.ts';
import { resolve } from 'aurelia';
export class FileImporter {
constructor(readonly fileReader = resolve(IFileReader)) {
}
}
This example demonstrates Aurelia 2's DI, injecting FileReader
into FileImporter
with resolve
. Similar to C#, it promotes loose coupling and cleaner, more maintainable code.
3. Dynamic Composition
Aurelia’s element enables dynamic composition of views and view-models. It acts like a custom element but without requiring a specific tag name, allowing for flexible and reusable UI components.
Inside the view model being used with , you have access to all of Aurelia's standard lifecycle events, along with an additional activate method that can be used to initialize or pass parameters to the view model.
Using the au-compose element in practice:
<template>
<h1>Main Application</h1>
<au-compose component.bind="viewModel" model.bind="{ title: 'Aurelia 2'}"></au-compose>
</template>
This example showcases in Aurelia 2, acting as a dynamic component factory. It allows for flexible composition by binding a viewModel and passing a model, enabling reusable and modular UI components without hardcoding specific elements.
How It Works:
Dynamic Composition: The component.bind attribute dynamically binds the DynamicComponent as the view model.
Passing Parameters: The model.bind attribute passes parameters to the activate method in the dynamically composed view model.
Separation of Concerns
One of the reasons I love Aurelia 2 is its clean Separation of Concerns through the MVVM (Model-View-ViewModel) pattern.
View: The UI structure is entirely decoupled from the logic. It simply binds to the ViewModel to display data and capture user interactions.
ViewModel: This is where all the logic happens. It controls the data, handles business rules, and updates the View, without worrying about how it's displayed.
Model: Aurelia keeps the core application data separate from both the View and ViewModel, maintaining clarity and focus.
This separation makes the application highly modular, easier to maintain, and much simpler to test, allowing for more flexible, scalable code.
Conclusion
In this post, I’ve focused on just three powerful concepts from Aurelia 2—Event Aggregator, Dependency Injection, and Dynamic Composition—but these are only a small part of what the framework has to offer.
Aurelia 2 is packed with features that help build clean, scalable, and maintainable applications.
To get the full picture and dive deeper into its capabilities, I highly encourage you to explore the Aurelia 2 documentation for a more comprehensive understanding.
PS: This is my first post, and I hope you liked it!
Top comments (6)
Just from what I read here, it reminds me of NestJS but with templating. I'll definitely have to take a look at it. I do live Astro though. I've been using it for about 2 years now.
Aurelia 2 offers a modular architecture and strong templating, similar to NestJS but with more focus on data binding and flexibility. If you enjoy Astro, Aurelia's reactive, component-driven approach is definitely worth exploring!
People sleep on Aurelia because it's not a big name framework. But, mature developers realise that eventually it comes down to the right tools for the right job over trends.
Absolutely agree! It's all about choosing the right tool for the job, and Aurelia delivers where it counts.
Well done!
Thanks!