Ionic 3’s lazy loading is bad for large apps
It’s been months since this post and no update from Ionic, other than a blog post describing two bad workarounds for their bad architecture and bad lazy loading. As such I’ve unfortunately given up on my dream of one code-base for mobile and web. We’re continuing to use Ionic for mobile for now, since lazy loading has less of an impact when you just load the app from the phone hard drive. For web we’ve moved to Angular Material for UI, which is nicely modularized and doesn’t interfere with good Angular architecture. I’m still hopeful that one day Ionic will provide better lazy loading support, but I have no reason to believe this will be in the near future.
I was excited for Ionic 3, it looked like we were getting lazy loading and an improved way to do “deep linking”, with the urls living on each component instead of having to be all listed in the main app module. “Yay!”, I thought, “what a great step towards a more modular, reusable, and testable architecture”. I even mentioned this in my Ionic 3 blog post! But…ooops, that was a mistake, as soon as I moved past the absolute simplest example my dreams shattered.
Angular lazy loading, modular design, and folder-by-feature
I’ll be comparing what Ionic is doing to how vanilla Angular works, so if you don’t have that context here are some links. Here’s an example of how an entire module is lazily loaded, complete with a service and multiple routed components: https://github.com/roblouie/lazy-loaded-module.
If you don’t know about folder-by-feature, here’s a quick explanation: https://medium.com/@cesarmcferreira/package-by-features-not-layers-2d076df1964d the official Angular style guide goes deeper into it: https://angular.io/docs/ts/latest/guide/style-guide.html#!#application-structure-and-angular-modules. Also, nowhere in the Angular docs, even in the simplest introduction tutorial, do they ever group code by type.
Trying to lazily load in Ionic 3 beta
So, since Ionic is built with Angular, I naively assumed it would work the same way, and I could start creating awesome features that could be reused everywhere. I was really excited to create a new blog post on building lazy loaded modules so I created a new folder, a new module, and added a couple of components. I gave each component the new @IonicPage annotation and fired up the app!
...lazy-load/page-two.component.ts has a @IonicPage decorator, but it does not have a corresponding "NgModule" at ...lazy-load/page-two.module
So, if you use the @IonicPage decorator, you must also make a module for the page. Well, okay, that’s really not that different from Angular, the router points to the module to lazily load, and then once that module loads it must take care of it’s own routing. I removed the @IonicPage from the SecondPageComponent and instead just tried to push it directly onto the nav stack from my lazily-loaded component.
Runtime Error Uncaught (in promise): Error: No component factory found for SecondPageComponent. Did you add it to @NgModule.entryComponents?
And yes, I did try adding it to the lazily loaded module’s entryComponents, but no dice.
What Ionic evidently wants you to do
Ionic, evidently, wants you to write a bunch of spaghetti code that’s hard to reuse, isn’t isolated at all for testing, and that results in a giant list of files where you can’t find what you want. Meaning they want you to forget about Angular best practices, real modules, modular design, and folder-by-feature, and go back to the old-timey folder-by-type structure.
They want you to only lazy load pages, and they want you to create a module for every single page you want to lazy load. That is dumb, like really dumb. They made a script to generate the modules for you, but really that’s just making a robot be dumb for you.
Angular: Check out this self-contained admin module you can reuse in any app by simply copy / pasting this folder! Your app gets to choose whether it eagerly or lazily loads the whole thing.
Ionic: Here’s a giant list of pages and a giant list of services, have fun actually reading the code to find out what pages depend on what services and good luck getting everything over to a different app! Also you can only lazy load pages and you have to make a module for each one.
I’m not usually one to complain but…
I have loved Ionic for quite some time and I’ve never been a complainer. When we wanted to move to Ionic 2 but it was missing a couple core features I didn’t complain, I created my own environment variables and unit testing config, the latter of which became the official Ionic test config. This time though I think it’s a bridge too far, I don’t think I’m going to write my own Ionic module loader.
So, here’s my first complaint against Ionic. Your lazy loading is bad and makes me feel like you are completely out of touch with how Angular and applications in general are built. Please fix it so I can love you again. I know for sure you are lazily loading modules, so why can’t those modules provide services that are scoped to that module exactly like Angular does? Why can’t those lazily loaded modules have multiple components that can be pushed onto a nav stack? Why are you seemingly dictating a folder-by-type architecture? Even Ionic 1 allowed for folder-by-feature, that’s how we built apps with it.
I would love for someone to tell me that I’m wrong, that I don’t understand, or that I missed some key information. Please make me look stupid for complaining about this and show me what I missed. Tell me this is just a temporary quick fix to speed up the ~10 second startup times and a better solution is being worked on. Tell me this will be fixed soon, I know this is just a beta release. Please?