I’ve spent the past four days with vNext
and like to share my experiences.
What did I do?
I’ve tried to port one of our internal apps from Aurelia 1 to Aurelia 2.
It’s a rather small app with only six views (3 list views, 2 detail views and 1 special case), but it uses the same codebase as our largest Aurelia app. The list views contain lots of complex components, filters, and actions and the detail views use highly integrated stuff like custom validation renderers.
It’s an intense test and beats the hell out of realworld and other toys.
Summary (tl;dr)
- It was a rough ride (as expected, in pre-alpha), but I really enjoyed it. I originally planned to try Aurelia 2 for only two days –but here I am, in the midst of day 5 and still fiddling with it. It gripped me
- I didn’t get as far as I hoped, but most of what I saw was quite encouraging.
- I strongly encourage more people to give it a try. (Well, maybe wait until the router is in better shape.)
How did it go?
The good
-
The core team! Huge thanks to @jwx, @fkleuver, @bigopon, @EisenbergEffect and all the others for being very helpful via Discord and the issue tracker. I felt very welcome!
-
The build process is much simpler than in Aurelia 1. I’m sure this will help many people who want to give Aurelia a try. For example, for webpack it’s a very straight forward configuration. I really don’t miss
aurelia-bootstrapper
, the buggyaurelia-polyfills
, and all the other cruft.aurelia-loader
is used to implement many of the conventions that made Aurelia 1 so nice and easy to work with. (With some caveats – see below). -
Writing tests is incredibly easy. I’ve found several issues in Aurelia and it was straightforward to write test cases that reproduced the problems (example 1, example 2). (I didn’t write any test for our own app in those four days.)
-
It feels very familiar. Many things, including complex stuff like
I18N
, work pretty much exactly as before.Hadn’t it been for the router and several bugs I encountered, I’m quite sure I could have ported the whole app in a day or two – including converting it to TypeScript with almost no prior experience in TS (see below).
-
Several tiny improvements made me very happy. I really like that I don’t have to manually specify
@inject
anymore. And it’s nice that the topmost<template>
wrapper is no longer necessary in every HTML file.
The not-so-good
Please take everything below with a large bucket of salt. I’m fully aware that I did the equivalent of walking onto a large construction site and trying to move in and live there. I know I can’t expect the elevators to work and the walls to be painted.
That being said, here’s what I found:
-
The router, again! The old router was barely useable for us. But with custom forks and fixes for
router
andhistory
, we could make it work.The new one is (currently!) much worse. It doesn’t fulfill any of our core use-cases. Its current interface and mode of operation are often the complete opposite of how I would have approached it. I gave up on it after the first day and had to fall back to just porting our most complex view instead of getting the whole app up and running.
That being said, the team assured me that the router is “just not there yet” and will work as I expected. I’m not fully convinced, but I’ll give the team the benefit of the doubt and wait for what’s coming.
-
I miss the old
<slot>
s. The new Shadow DOM implementation has drawbacks for our use-case. -
I felt the Second-System Effect in several places. While v2 is much simpler than v1 in some aspects (see above), it feels more complicated and over-engineered in others. It’s not really something concrete I can point at, but the “over-abstraction spider sense” I’ve developed over the past 20 years started tingling.
This is highly subjective and I’d have to spend more time with the codebase to better articulate what I mean, but here are some rough examples:
-
Lots of new interfaces where you have to know both the Interface and the implementation (eg.,
I18N
) or have to know at what level of the abstraction you’re supposed to enter. (eg., shall I injectIDOM
orHTMLDOM
?)This seems to be caused in part by Aurelia trying to fit many more use-cases, which automatically makes it more difficult for users to find the correct angle for their particular use-case.
-
Interfaces whose benefit I don’t understand. For example
IRouter
. My take is: the odds that I would replace the router and the replacement would still adhere toIRouter
are close to zero. So why have that extra layer of abstraction in the first place? -
aurelia-pal
was quite straight-forward to use. ButIDOM
/HTMLDOM
can’t be used until Aurelia has been started (which complicated some of our use-cases.)
-
-
The conventions and
aurelia-loader
interact with some features in unexpected ways, causing things (currently!) to sometimes stop working unexpectedly. The alternative – having to manually annotate everything – would eliminate much of the elegance that drew me to Aurelia in the first place.Some examples:
-
<import from>
(the new<require from>
) can’t be used to import routing components – at least I couldn’t get it to work. I had to use@customElement({dependencies:…})
on the class instead. -
<import from>
(for normal components) stops working if the corresponding class has a@customElement
or@view
annotation. (Which is amplified by the previous point.) -
The auto-injection stops working as soon as you annotate one of the constructor arguments – which you’re sometimes forced to do, due to the way interfaces / implementations are currently structured.
For example,
@aurelia/i18n
requires you to inject as@I18N i18n: I18nService
instead of justi18n: I18nService
ori18n: I18N
(for reason’s I don’t understand). But then you have to annotate all your constructor arguments for that class or DI will throw up.
-
Other stuff
This was also the first time I’ve given TypeScript a serious try. When I last attempted to adopt TS – 4 years ago – it was a horrible experience and I bailed within hours.
This time it was much better. At first I tried to apply a strict TS configuration. But this created way too much friction and turned my “migrating to Aurelia 2” task into a huge “migrating to TS” task – which was not my goal for this week. After adopting a more lenient approach, it started being useful without being very obstructive.
I’m still not fully convinced TS provides many benefits for frontend apps. Many of our regressions and bugs arise between templates and code – where TypeScript can’t help you. But it also doesn’t hurt, so I’ll continue to use it for now and see how it goes. And I’ll definitely consider adopting it for our NodeJS backend, where it could be much more helpful – if compile times don’t get out of hand.