SSR Angular/Ionic — well kind of
Ionic is a framework we all have heard of at some point in our development life cycle. In simple terms, Ionic takes our js code (typescript transpiled ) and puts it into a web-view with ability to access some native apis for mobile devices, which we can upload to the Apple store/ Google play store. Mobile app stores take a look at our code and check for code that may be harmful or disregard any of the stores' rules and regulations. Which makes SSR for mobile apps, well, very counter-intuitive and hard.
Honestly, this workaround was forced by a requirement from a client, to allow UI updates without going through the store.
Let's begin with the basics of how Angular builds components.
At the beginning when angular compiles it builds one large object of templates and classes in which from there the app works from. This an extremely simplified explanation, but this was the idea behind the solution.
@Component({selector: ‘app-ssr’,templateUrl: ‘./srr.component.html’,styleUrls: [‘./srr.component.scss’],})
So essentially, we are telling the component to go to ssr.component.html and fetch the string from there for use. So why not use a function for this :
@Component({selector: ‘app-ssr’,templateUrl: PageHandler.getPage(‘loginPage’),styleUrls: [‘./srr.component.scss’],})
In the component above we tell angular to run the function and it will return a string (*note*: must be synchronous code). If I have an error the app won't compile saying it is missing the template.
So now we know that we use the function to get the data, we can build an object the has key:value of pageName: template
const pageTemplates = {loginPage: ‘<a>Login</a>’fallBack: ‘<a>Fall Back</a>’}@Component({selector: ‘app-ssr’,templateUrl: pageTemplates.hasOwnProperty('loginPage) ? pageTemplates['loginPage'] : pageTemplates['fallBack'],styleUrls: [‘./srr.component.scss’],})
In the gist above, we have told Angular to see if there is a loginPage template, if not then fall back to the fallBack template ( angular will fail to build if there is no template).
In order to update the pageTemplates with the latest templates, we can run a function before it and do whatever we want to the global data (such as pageTemplates Object)
PageFetcher.getUpdatedTemplates().then(() => {platformBrowserDynamic().bootstrapModule(AppModule)})
Since the bootstrap function runs after our fetcher it will use only the update templates for compile run.
Our getUpdatedTemplates will fetch the server for the updated templates and will change the pageTemplates to the updated ones, and when our angular component will go to that object to get the template, it will get the one we took from our server.
Boom you just used ionic with ssr. well kind of, there are limitations to this, such as passing new and updated functions which is currently something I'm checking on how to do.
This idea also works with the styles obviously.
Some answers to expected questions:
- fetching after build and using InnerHTML won't work as expected when it has the angular fun stuff like (click), and {{aVariable}} since Angular escapes it as harmful.
- This will hurt the performance of init run, but after that, it works like a charm.
- I would have some sort of or fallback component or something in case there is an issue with the fetch or support for offline
- This hasn’t been tested fully and was just a discovery I found that I couldn’t find anywhere online.
Have fun with this, and explore the limitations, there is no reason to be coupled to the mobile app stores.
vive la revolution