[00:00:00] Let's jump into a little bit of an introduction. I'll give mine, and then I'll pass it on to Bertrand. My name is Robyn Dalgeish, and I'm a solution architect at Rangle. We help level up teams, and our aim is to remove ourselves from that and have them be amazing on their own.
[00:00:22] Yeah, and I'm happy to chat today, and I'll pass it over to Bertrand to introduce himself.
[00:00:28] Absolutely. My name is Bert. I head up strategy here, and I lead the teams that help our companies make decisions, choose frameworks, and find a path to success in whatever they're trying to accomplish.
[00:00:42] We're really into static site generation and server-side rendering as a solution. And we felt that, in the Angular community, we don't talk enough about it. We want to add our voice and provide something that's interesting and useful to solve some of the problems you guys may face when trying to build apps.
[00:01:00] So we'll be covering static site generation (which we'll occasionally refer to as SSG) and server-side rendering as well. We'll also cover the difference between the two as we go through this process. On the right side is an app that's built using some of the methods, patterns, and tools that we'll be discussing.
[00:01:21] For this demo, it's a very simple site. You can see that it's what you would expect from an Angular application. It's interactive, with hover states, and the header changes. You can click links and see it navigate instantly. You can navigate back home, and there are inputs and everything.
[00:01:41] So on the surface, it behaves exactly like every Angular application you would have seen or written. But what's special about it is that almost every page you saw there was statically generated or generated on the server. We'll go through how we built this and what you should know to get started on that journey, should you need to.
[00:02:08] So I'll get us going. There are three parts to this intro. First, we'll spend a few moments covering why speed matters. I think a lot of the people in this room probably already know, but I think it's useful for us to go over it and provide a way of understanding why we're having this webinar to begin with.
[00:02:33] We're very obsessed with speed, and we'll talk about why we're obsessed with speed. The truth is, we have found that static site generation and server-side rendering are essential tools in our toolbox to achieve the performance we need in our applications. To achieve speed as a result, we have to apply different rendering strategies.
[00:02:51] The default and what we've seen in most Angular applications is client-side route rendering. We'll also cover the other two: SSG and SSR. I'll give you guys a quick intro to a meta framework, which is a framework on top of Angular that makes building these applications super easy, super fast, and super enjoyable. That's a big deal.
[00:03:08] And we'll talk about why that's also a big deal. Overall, we hope that you will take away a better understanding of how to essentially build the highest-performing Angular application that you possibly can. So, on that note, why does speed matter?
[00:03:23] Speed affects users, and this has been studied over and over again. The smallest increment of time that we can discern as human beings is around a hundred milliseconds. Beyond a second, we tend to lose our focus on the task, and our eyes start to wander. Beyond 10 seconds, we tend to abandon tasks altogether. So, speed has an impact on the user, even at the scale of a hundred milliseconds. I think a lot of people intuitively understand this, but it's something else to really see it in practice.
[00:03:54] We have seen this over and over again in our work. Another thing is that speed affects your SEO. Google uses page speed as a ranking factor for pages and looks at a few key metrics. One of them is LCP, which stands for Largest Contentful Paint. It refers to the time between the page starting to appear and it displaying something that looks at least above the fold and complete. Google's benchmark for good LCP is under 2.5 seconds.
[00:05:04] Lastly, there's cumulative layout shift, which is often observed in client-side applications where different pieces of the page load one after the other.
[00:05:18] The view that the user sees keeps shifting and moving. This is actually most impactful on mobile, but we also see some impact in terms of desktop. The cool thing about the topics we're going to discuss is that they really address these three key points and are truly effective tools to help score higher in these categories.
[00:05:45] Lastly, speed affects the actual business you might be working for or running yourself. There was a study conducted 10 years ago where Amazon found that every hundred milliseconds, so that's a hundred milliseconds coming up, cost them about 1% in sales. This finding has been reproduced over and over again.
[00:06:07] We conduct a lot of testing with our clients, and we have also observed similar impacts. Akamai released a study just a few years before Covid (so that counts as yesterday, right?) that shows every hundred millisecond delay in website load time can reduce conversion by around 7%.
[00:06:26] The root cause for this shift over the last decade and a half is really mobile usage and the increasing expectations that customers have. What we take from this is that almost every year or every few years, customers' expectations of site speed and site load just keep getting higher and higher.
[00:06:47] That's why we're discussing this today. It's crucial and adding this to your toolkit can be highly beneficial. Now, let's delve into rendering strategies because we've been mentioning SSG and SSR, and I want to provide some context.
[00:07:03] The default behavior in Angular, when you run the Angular CLI and create an app, is that on the initial load, the app is not rendered. There's the index, there's the root, and the app becomes active after hydration occurs, which happens once the browser has downloaded all the Angular files and assets.
[00:08:12] This is really what we're going to be talking about today. How do we actually do that? And when do we do it?
[00:08:18] A lot of acronyms. Well, two, to be precise. SSG and SSR. The first method of pre-rendering is static site generation. SSG refers to rendering at build time. What we do there is when we're building our application, this could be in the CI/CD, this could be locally, but before sending it to the server, we're going to go ahead and generate the HTML.
[00:08:42] And then when the user requests it, they get that same HTML sent to them every single time. Because we already have the HTML, it's really fast and we can cache it. And once they have it on their local browser, they see a page loaded instantly and then it becomes interactive within a hundred milliseconds, which is exactly what we want, thanks to Angular hydration.
[00:09:09] Furthermore, we have server-side rendering. Server-side rendering is a bit different, as the HTML is actually generated at request time. We don't do this on the CI/CD pipeline. We have a server, and when somebody asks for the page, we just go ahead and generate the HTML and send that HTML down to them.
[00:09:29] When we consider when to use server SSG or SSR, it really depends on what we're trying to build. Our general advice is to use SSG whenever possible. So think of when you have marketing pages in your applications. Think of when you have blog posts in your applications. Think of when you have product listings in your commerce application. All of these are great use cases for static site generation. A page like this, for instance, since everybody is going to receive pretty much the same page. And then when it becomes interactive, it can go ahead and load some of the more dynamic pieces like price or any experiments or any cart count.
[00:10:12] In the case of SSR, it is best suited when pre-rendering ahead of the user's request is not possible. This often occurs when users require frequently updated data or when they access specific pages like an account page.
[00:10:36] It's important to note that both SSG and SSR can be used within the same application. Some pages can use static generation while others can use server-side rendering. In either case, they are pre-rendered, but with different timing: some at build time and some on the server. You have the flexibility to mix and match them as needed. For example, an "About Us" page can be completely pre-rendered using SSG, while an account page can be server-side rendered using SSR.
[00:10:50] Now, let's discuss this in the context of Angular. The problem we've observed is that there aren't enough SSG or SSR Angular applications in the wild. When we talked to our clients and the community, we discovered a few key factors contributing to this. The main issue is that it can be quite challenging, not only to set up but also to maintain. Using Angular Universal, which is provided by Angular, requires careful consideration of how to implement pre-rendering and server-side rendering and how to instruct the framework to choose between the two when necessary. Additionally, since the rendering occurs on the server, there are complexities involved in writing API routes to handle the data retrieval process. As a result, many Angular developers have turned to Next.js for applications that require server-side rendering or static generation, which is unfortunate.
[00:12:30] Fortunately, the Angular community has been working on a solution outside of the Angular core team. Brandon, from the NgRx team, is leading this effort. They have developed a framework called (or AnalogJS) which acts as a meta framework built on top of Angular.
[00:12:51] Using Analog, you can easily support server-side rendering (SSR) and static site generation (SSG) while enjoying a great developer experience. Additionally, Analog allows you to create API routes to enhance the overall application experience on top of Angular. I will demonstrate how we used Analog to build the site on the right side and hopefully provide an entry point for using SSR and SSG in the Angular ecosystem.
[00:13:24] This will be a fast and concise overview as the framework itself is quite powerful.
[00:13:28] To begin, Analog provides a scaffold. By running an npm or yarn command, it sets up a standard Angular application with the necessary server components already configured. Pay attention to the `main.server.ts` file and the server files. They are similar to what you would get from the Angular CLI, but they are prepared to handle the heavy lifting required for server-side rendering and static generation. It's that simple, and I'll demonstrate it with some code.
[00:14:13] Before we dive deeper, there are a few key concepts you need to know about Analog to get started, and we'll cover those shortly.
[00:14:21] One of the notable features of Analog is the way you define paths or URLs for navigable pages. Analog takes control of the routing for you, which is crucial. It enables Analog to handle serving SSG or SSR pages and determine when to use each approach.
[00:14:43] Analog takes care of the routing for you, following a pattern that may be familiar if you've used Next.js. Under the `src/app/pages` directory, you simply export TypeScript files to define your pages. The path of the file becomes the corresponding URL. In this example, there are two files: `index.page.ts` and `[roomId].page.ts`.
[00:15:06] The `index.page.ts` corresponds to the page you see on the right side. It represents the index or home page. The `[roomId].page.ts` file is a bit different, and we'll explain it shortly. You can create additional files like `about.page.ts` or `contact.page.ts` under the same directory to map them to their respective URLs.
[00:15:35] The mapping is straightforward and supports nested routes as well. To create nested routes, simply create a folder. For example, instead of the room page being located at the root of the domain, it can be nested under `/rooms/room-name`. You can nest routes to any desired depth, although I don’t know why you would want to go further than 16 or something, but you can if you really, really want long routes.
[00:16:06] Now, let's discuss the square bracket notation `[roomId].page.ts`. This notation allows for dynamic routes. Each room has its own page, such as a signature room or a deluxe room, and the data for each room can be viewed individually. When a URL matches the pattern `/room/something`, the value after `/room/` becomes available as a page parameter called `roomId`. This variable can be used to fetch the corresponding room data from a database or CMS and render it dynamically on the page.
[00:16:53] This approach is incredibly powerful. It allows you to create dynamic systems that work seamlessly from both server-side and static site perspectives. Additionally, there's a `server` folder where you can create APIs to fetch data. These APIs can be placed under `server/routes` and will appear under `/api/` followed by the file name (e.g., `/api/rooms`). It's effortless to define your endpoints in this way. When you deploy your application, both your APIs and pages will be deployed together.
[00:17:34] There's also a file called `vite.config.ts`, which we will discuss later.
[00:17:47] Once you have a page, it looks like a standard Angular component. In the example of the index page, it consists of an app hero section with a slider that changes the background every few seconds, a booking form in the middle, and a list of rooms. This is a familiar page structure that you may have created numerous times before. Simply by placing it under the `src/app/pages` directory, it is now server-side rendered by default. There is no additional configuration required. This is the smooth developer experience we've been highlighting. In a way, it resembles building HTML or PHP sites, but with the advantage of leveraging Angular.
[00:18:40] That's it! Once you have the structure we discussed and place your components under the `pages` directory, they will be server-side rendered. When a user makes a request, your server will generate the HTML and send it. Once it's received, the page will function as expected. For example, a carousel component will behave like a carousel.
[00:18:59] A form will function as a form, and rooms will behave like rooms, including all the desired flourishes and CSS animations. Once you have Analog set up, the rest of your application will largely remain the same. We've witnessed people migrating fairly large applications with minimal code changes. It's truly impressive and powerful.
[00:19:26] I mentioned `app routes`. If you're familiar with Lambda, it's a simple TypeScript file that you export. Once exported and deployed, it runs and handles events from the API routes. You can customize the route as needed, and even add API versioning for backward compatibility. Inside this file, you can write asynchronous (or synchronous) functions to perform logic such as fetching room data from a database or CMS, and then return it. This creates a JSON API.
[00:20:09] By placing this TypeScript file in the `server/routes` directory, you not only enable server-side rendering but also provide API routes that your server-side rendered pages can access to retrieve data, such as a list of rooms to render. It's efficient, co-located, and almost feels like magic.
[00:20:32] Additionally, we've seen people utilize this setup to proxy other APIs. It's a popular approach for front-end teams to create their own APIs that interface with backend APIs.
[00:20:42] Finally, the last piece of the puzzle is how to achieve static site generation (SSG) instead of relying on server rendering for certain pages. This is where the `vite.config.json` file comes into play.
[00:20:58] Inside the `vite.config.json` file, you can define the routes that you want to be pre-rendered as static pages. Instead of being server-side generated, these routes will be statically generated during the build process. You can specify routes like the about page, the root of the blog, or even individual blog posts to be statically generated. Any pages not listed in this configuration will be server-side rendered.
[00:21:27] The Angular routing module is under the hood and can still be used. You can utilize the `RouterLink` and other Angular routing features as usual. The framework takes care of mapping the routes based on the directory structure. While this is the default behavior, you have the flexibility to customize it if needed.
[00:21:49] It's worth noting that people have successfully set up analytics tied to the Angular router with minimal changes. The framework handles it seamlessly.
[00:22:01] Surprisingly, that's all there is to it! You have now learned how to build an SSG/SSR Angular application in about 20 minutes. You've got this!
[00:22:13] We can't wait to hear about your experiences, whether it's your successes and discoveries or any feedback and challenges you may encounter. Please share your experience reports with us.
[00:22:33] [Question from the audience] Regarding the question about how these SSG/SSR sites are served, typically SPAs (Single-Page Applications) are statically served with tools like Nginx. Similarly, SSG/SSR sites can be served using Nginx or other web servers. The generated static files can be deployed and served like any other static files.
[00:22:45] That's pretty cool! Analog is built on Nitro and Vite technologies. When it comes to server-side generation, it's important to note that it requires a running server. While it's common to build the application and distribute the build to a CDN or storage for static generation, for server-side rendering, you need an active server.
[00:23:20] The great news is that Analog already includes a server within the framework. When you build and deploy your application, it will work seamlessly without any additional configuration on platforms like Vercel, Azure, CloudFlare, and Netlify. With a bit of configuration, you can also deploy it on platforms like AWS, Digital Ocean, Firebase, and Heroku.
[00:23:42] In other words, there may be some configuration required for certain platforms, but overall, you'll build your Analog application and deploy the bundle with the pre-configured platform settings. This allows for smooth deployment on various hosting platforms. Does that answer your question?
[00:24:03] [Question from the audience] Normally, for a single-page app, you can deploy it to an S3 bucket and associate it with a domain name, resulting in a cost-effective hosting solution without the need for a virtual machine or server. However, with Analog and server-side rendering involved, you will require a server or virtual machine to execute the code remotely. This may entail a slightly different hosting setup compared to a purely client-side application.
[00:24:38] Yes, with an asterisk. For instance, you could take this application, put it in a Docker container, and deploy it. Then you would have a different runtime cost compared to using a storage bucket. However, the trend in server-side applications is moving towards serverless deployments. In practice, people deploy these applications on platforms like AWS, Azure, Vercel, DigitalOcean, and others using serverless Lambdas. This means there isn't a server running all the time. Instead, a server runs when a request comes in, generates the page, and sends it.
[00:25:19] The affordability of using a storage bucket, like you're accustomed to, changes in this case. Lambdas may be more expensive, but you gain speed and hopefully business benefits. The key advantage is that you don't have to worry about provisioning or managing servers.
[00:25:37] Another great aspect is that when you use platforms like Vercel and AWS, you can leverage Edge Lambdas, which bring the server closer to your end customers, reducing latency. We've used CDNs extensively in certain application domains and achieved latencies as low as double-digit milliseconds for the first byte seen by the customers.
[00:26:13] So, in short, the answer is Lambdas, and the longer answer is what I just explained.
[00:26:19] I see a question about deploying to Azure. Absolutely! Azure is a first-class supported platform for Analog, along with Vercel, CloudFlare, and AWS. There is documentation available, which we will provide to you. Deploying on Azure is straightforward, requiring minimal effort. In fact, we have deployed this exact example on Azure, showcasing its effective utilization. You can use Azure Functions and other hosting services, such as Azure Web App. There are multiple options available to you on Azure.
[00:27:00] [Question from the audience] The application I work on is probably the antithesis of static. It's essentially a customer portal. When it's deployed on platforms like Azure or AWS with server-side rendering (SSR), where HTML is generated at request time, almost every single page I work on needs to be rendered because it contains specific data for each customer. So, what's the benefit in this scenario? I imagine there's a difference in latency between the browser making an API call and the server making the API call and then rendering it. However, the browser still needs to render all the HTML. Maybe there won't be as much cumulative layout shift (CLS), but is the trade-off worth it?
[00:27:49] Thanks for bringing up that point. I missed mentioning it earlier because I was so focused on SSR and SSG.
[00:27:55] I think it's worth discussing when to stick with client-side rendering. In the use case you described, such as a dashboard or a data-intensive application that varies greatly per user, our experience suggests that it's not necessary to use SSR or SSG. These types of applications are often behind a login wall, so there's no SEO benefit.
[00:28:19] Moreover, these applications tend to make numerous API calls, all specific to each individual user. In such cases, the value of SSR or SSG is diminished. The dashboard use case is one where we recommend sticking with client-side rendering to avoid adding unnecessary complexity to your stack.
[00:28:40] The only exception is that the API routes will always be server-side. Angular provides a feature called state transfer, which means you may need to make multiple database calls to different systems. If those systems are significantly faster on the server side than on the client side, and the performance improvement is worth it, you might consider using SSR. In the past, we have used GraphQL to address performance issues caused by a large number of API calls, leveraging HTTP/2.
[00:29:23] So, once again, my lengthy way of saying is that for those dashboards, it's best to stick with client-side rendering. However, for everything else, you should definitely consider using SSR or SSG.
[00:29:31] I'm guessing the application you're working on has a marketing site before the login, right?
[00:29:37] Well, within the organization I work for, there are multiple applications, some of which have marketing aspects. The specific application I work on is all behind a login, and the API calls are made to internal systems that are currently not hosted on a public cloud. So, I don't believe SSG or SSR will work for our case. However, there may be other applications within the organization where it could be suitable.
[00:30:07] We have another question regarding when there might be a stable release.
[00:30:11] The reason why it's in beta is not because it's not being used, but rather because there are still ongoing improvements and additional functionality being developed, which may result in breaking changes.
[00:30:28] It's important to understand that Analog is a meta framework built on top of a stable version of Angular, such as Angular 16 or Angular 15, depending on the version you're using. The core Angular functionality is very stable. Analog primarily provides a set of tooling and features on top of it.
[00:30:48] While it's currently in beta, it is already being used in production environments. The stable release is expected later this year, depending on the feedback from current users. However, it's important to note that the beta phase does not mean it's broken or unstable. The team behind Analog has focused on ensuring API stability, and thus far, there have been no major issues.
[00:31:23] And when errors do occur, they actually make sense, which is a win in my book compared to the old CLI, as you all may remember.
[00:31:33] It has been an awesome engagement. Thank you, folks. Is there anything else?
[00:31:40] Thanks, everybody, for joining us. Go ahead. Sorry, I interrupted your thank yous.
[00:31:45] Thank you so much for joining. We appreciate your questions. This has been fantastic.
[00:31:50] If there's anything we didn't cover or didn't go into enough detail about that you really wanted to know, but didn't get a chance to ask, feel free to send us an email and request it. We're happy to provide any additional information or assistance.
[00:32:05] Great. Thank you, everyone. This has been great. Have a good day.