So I've got to admit, when I realised a couple of years ago that a plain Angular application wouldn't render dynamically-generated metadata, I was pretty surprised. I kind of felt like it was one of those huge oversights like you sometimes hear about on big civic projects where they build a tram but forget to have any platforms or something like that. Surely half the internet is metadata? And surely half the point of JS frontend frameworks is to get data out of an API and render it? But anyhow... Angular Universal to the rescue.
I've recently finished converting some of our plain Angular pages to Angular Universal, and I decided to do the same with my blog so that I could put links to it on social media. Here's how I did it.
I've based a fair amount of the first part of this on this tutorial from Twilio.
In summary, if you've already got AWS CLI set up, and you've got an Angular application you'd like to make Universal, you can accomplish it in a couple of steps:
# convert your application to use Universalng add @ng-toolkit/universal# set it up so you can deploy it to serverlessng add @ng-toolkit/serverless# deploy it to serverless!npm run build:serverless:deploy
There's quite a lot more in the Twilio article, but I don't want to steal someone else's thunder. It's pretty cool - you'll end up with a Lambda function that runs an Express server to serve your Angular Universal site, an S3 bucket with the site in it, and API gateway to serve it over, and a CloudFormation template to orchestrate the whole thing. The trouble is, your site's got a URL like this:
And who wants that?
(You may also find, depending on whether your application makes use of the browser APIs, that the conversion to Universal isn't quite as easy as all that. Generally it's probably easier to make the decision to do it this way earlier on in the life of the project. But people always say that, don't they?).
We're going to do a few things in this part:
AWS CloudFront is a content distribution network, which in brief means it will cache versions of your app in AWS infrastucture around the world where it's likely to be the most useful. I suppose if you wanted to you could configure your DNS to point directly at your API endpoint, but the performance can be a little sluggish, plus you may want to serve other applications under the same domain, so you'll need a way to route your traffic. There is a charge for CloudFront, but it's fractional - on the free tier it's 50 GB of data transfer out, and 2,000,000 requests per month.
The AWS documentation on setting up CloudFront is actually pretty great. If you don't already have an AWS account, set one up (you'll have to give them your credit card details but don't worry, there are very few things you can use that will cost a lot of money and there are plenty of ways to make sure you don't spend more than you want to). Here's a couple of gotchas that took me a while to figure out:
Save your Route 53 changes and save your CloudFront distribution. The changes can take twenty minutes or so to propagate so maybe now's the time for a celebratory coffee/beer/Coke/walk around the block.
This is starting to get quite long, so I'm going to cover setting up the application itself and configuring your Bitbucket Pipeline in a different post.