Web Studio is here! An enhanced experience to make it easier to create, preview, and collaborate on your website contentLearn More
Introducing the first dynamic page server side rendering starter for Angular featuring Agility CMS. This utilizes SSR capabilities of Angular 18 to pre-render a users sitemap into pages served statically for fast page delivery and SEO optimization.
This build features a streamlined architecture and easy to understand development patterns common to Angular developers that will naturally fit within the modern language of the Agility ecosystem.
The repository can be found at https://github.com/agility/agilitycms-angular-starter Currently this version is located on the angular-ssr
branch
npm install
to install the Node ModulesYou will need to get the following from the Agility Manager;
GUID
API_PREVIEW_KEY
API_FETCH_KEY
LOCALE
SITEMAP
https://manager.agilitycms.com/settings/apikeys
You will need to populate an .env file in the root of your project as follows.
This will use dotenv.config.json to write your environment.ts and environment.prod.ts files required by Angular. This approach avoids exposing your API keys to your Git repository.
AGILITY_GUID=e13c7b01-u
AGILITY_PREVIEW=true
AGILITY_API_PREVIEW_KEY=AngularPreview.6617c54b87588d941d32416a9dfb1e8fd9e556439984e8236ac75896e47ae02a
AGILITY_API_FETCH_KEY=AngularFetch.a20b40fd8cd25e02ba62ca5c3acbaae5512c1d633b51ea104ac28f9bc3b9d44d
AGILITY_LOCALE=en-us
AGILITY_SITEMAP=website
npm run dev
start the development servernpm run build
pre-renders the routes via agility-routes.txt then builds the production servernpm run start
starts the production servernpm run prerender:routes
pre-renders only the agility-routes.txtAlthough Angular's ng
commands are still available, we’ve introduced a number of steps in the building and serving of the Angular application. As such its advisable to use the npm run
commands above. However, if you still desire to use the ng
commands please be sure to run these prior to trying to run your application to generate the necessary environment and routes files.
npm run envinit
npm run prerender:routes
This feature works as a client side only feature to ensure changes are loaded directly from the API instead of using the pre-rendered page and content data.
Angular is built primarily as a client-side framework, designed to load an initial shell of the application in the browser and handle navigation on the client side. With this architecture, Angular’s built in router dynamically updates the content without reloading the page.
Angular can handle SSR for the initial page load, however, once the app is hydrated, navigation between routes is managed by the client-side router, which means http requests are visible and no longer Server Side. The Angular router doesn’t natively support dynamic changes to the base route or URL content without a full page reload.
Angular’s SSR can be thought of as a “Hybrid” SSR feature as it does not function the same as a more fully developed client router like in React or Vue.
This starter implements a TransferState functionality to reduce subsequent page requests from the client however if you want to completely eliminate client side requests you will need to serve the production build.
The Angular TransferState API is designed to persist data between the server-rendered page and the client, but it only applies to the initial load, not for subsequent navigation events. After the first load, if you navigate to another route, TransferState will not automatically fetch fresh data from the server.
Angular 18’s SSR functionality is definitely a step in the right direction for Angular however it’s clear there’s still room for improvement on connecting the the hydration flow from server to client when navigating via the Angular router.
Other Workarounds - Pre-render all page data and content lists
This does not include the boilerplate created by Angular however this is the basic overview of the starter architecture of what we’ve added to power Agility CMS.
This is a solution to using the Angular Router to avoid client side requests.
The way it achieves this is to pre-load the website data by running a pre-fetch process in Node when building the site.
This solution is comprised of 3 main files, one of which is already present in the base branch angular-ssr
prerender-routes.ts
- generates an agility-routes.txt file for Angular to prerender the page contentprerender-pages.ts
- generates a JSON file of all your Agility Pages, effectively a Sync mechanismprerender-content.ts
- generates a JSON file of all the content lists you requireTwo new build commands are introduced with this branch
npm run prerender:pages
npm run prerender:content
In order to pull data client side components have to be updated to first check the local JSON files and then set that as the initial TransferState.
import agilityPagesData from '../data/pages.json';
async preloadTransferStateData() {
let pagePath = this.location.path().split('?')[0] || '/home';
if (pagePath === '') pagePath = '/home';
for (const key in agilityPagesData) {
const pageKey = makeStateKey<any>(key);
this.transferState.set(pageKey, (agilityPagesData as any)[key]);
}
}
This has not been tested on websites with a large volume of pages or content lists. Anything pre-rendered will in-fact add to the build times of the application. As well, since the Angular Router is held within memory, all pre-loaded data is also held within memory adding to the application overhead.