How I made my blog cheap to host, customizable, and lightning-fast. - Part 2

3-29-2021 10:20AM

Part 1: Setting up — Azure DevOps and Our Headless CMS
Part 2: Building out our Angular Site — you are here
Part 3: Meet Scully, our Static Site Generator 
Part 4: Hosting on the Cheap
Part 5: Build and Deploy with Azure DevOps 

In Part 1, I laid out the stack from source control to release pipeline. We also set up a couple of accounts we'll need for our CMS and Source Control. Now let's get to the fun stuff.

We're going to build an Angular site here, but you could swap out your framework of choice if you'd like. The key is that you can hook up a Static Site Generator to it. We'll use Scully, but I don't see any reason you couldn't use Hugo or Gatsby or any of the others out there.

The Site

I put an extremely basic site together to prove out this concept. I've posted it over at Github. Feel free to do whatever you want with this site. I'll likely port back some features to it as I build them out for my personal blog and welcome any you might want to add. I should say upfront though that at this point it is hardly a blog. Just a site with an unstyled list of posts and an equally unstyled display of title/body.

If you want to skip this section you can just grab the code from Github and move to Part 3. The site is pretty simple, but there are a couple of things worth mentioning:

  • There is an interceptor that catches all requests to the Squidex API and tacks on an authentication header.
  • I added dotenv to keep the environment variables out of git. This is described a bit in the readme, but basically, you create .env.[prod/dev] files with your variables, and on npm start or npm build, it will regenerate your environment.ts files.

Here's how you can get started with it:

  1. Pull site down from Github
  2. create .env.dev and .env.prod files in root
  3. fill those files out per the .env.example file in the repo with details from your squidex client
  4. run npm start

Still here? Let's build a website.

First, we need to create an angular site. Open up your favorite editor (It's VS Code right?) and if you're new to angular run this:

npm install -g @angular/cli

Then run this (You can name the project anything)

ng new my-rad-project

You'll get asked a few questions. We want it strict. We want routing. You can pick the styles (I use SCSS).

Create our Components

We're going to need a couple of components:

  • list of blog posts
  • individual blog post
  • navigation
  • home page

We can create these with the following terminal commands:

ng g c components/blog
ng g c components/blog-post
ng g c components/nav-bar
ng g c components/home

Moving Around

Let's get some routing set up so we can navigate to these components. Open the file /app-routing.module.ts. We're going to modify the routes variable to map 3 routes:

const routes: Routes = [
   {path: 'blog', component: BlogComponent},
   {path: 'blog/:postSlug', component: BlogPostComponent},
   {path: '', component: HomeComponent},
];

When you put your cursor on a component name, you can press ‘Ctrl + .' then enter to import that component.

Finally, let's go into the /app.component.html file and replace all the contents with

<app-nav-bar></app-nav-bar>
<router-outlet></router-outlet>

If your server stopped running you can start it again and you should see a page that says "nav bar works!" and "home works!".

Let's add links to our nav bar control so we can check out the work we're going to do on our blogs component. Replace the nav bar file with this:

https://gist.github.com/milestonedev/99a28e813e44a0f73982c1256fa6fefb

Get our Data from Squidex

Since we're using TypeScript we need to start with our models. These interfaces will define the structure of the objects we're bringing back from the CMS. We'll create a "models" folder and add these interfaces:

https://gist.github.com/milestonedev/fc9ed791a94238e4eb9f65dd5736c58e

Now we have the structure, we can create a service to fetch the data. Run the following command in the terminal:

ng g s services/contentBackend

Fill the file with the code below. It just makes a call out to the Squidex URL that gives us back a list of all of our posts.

https://gist.github.com/milestonedev/3dc0136bdc2276691114b358583092ff

Adding Authentication

Awesome. Now we can pull in our posts, right? Not quite... We still have to handle authentication with Squidex. Good news though, we're just going to do this once. First we need to create a "services" folder, and add the following file to it, call it "squidex.config.ts"

https://gist.github.com/milestonedev/38b7cde7883bece925724637cf173bc7

Then we need to provide all of the environment variables. We do that in our environment.ts file:

https://gist.github.com/milestonedev/8ea0815f6520cb4201f122036f57dd3e

Next, run this command:

ng g interceptor services/contentAuth

This will generate an "interceptor" file. We'll use this to catch every request going out to the Squidex API and tack on an authentication header before sending it. Here's how we do it. This code is lightly modified from the official Squidex sample blog. You can find the original here.

https://gist.github.com/milestonedev/f3c7b6ab2567da4b60c637abd73c2cc6

Then we'll need to add the interceptor and the config to the providers section of our App Module.

providers: [
{ provide: SquidexConfig, useValue: DefaultSquidexConfig},
{ provide: HTTP_INTERCEPTORS, useClass: ContentAuthInterceptor, multi: true}
]

Now we should be able to make a call and get data from Squidex. Let's try it!

Listing our Blog Posts

We've got to have a way for users to go from post to post. We're going to create a list of every published post and just link each one. To do this, we'll edit the blog component we created earlier. Modify the Html and .ts files to look like this:

https://gist.github.com/milestonedev/1a9e16459edf0c7185bf6440c5bf870c

Now you should be able to run an ng serve -o and click the "blog" link in the nav to see any posts you have published in Squidex. Make an edit, come back and refresh, and things should update.

Display a Post

If you click the link on one of your published posts, you should have just seen: "blog-post works!". What we need to do is fill out that component so that it reads the slug from the URL and displays the correct story. Here's the content for both the Html and the .ts file.

https://gist.github.com/milestonedev/ec5f8cd0e429078e359c3eb2c72860a7

 

Notice we're calling a new method on our ContentBackendService. Let's open that file and add the new method:

https://gist.github.com/milestonedev/e6d44a7e412987c3191c8ebc86567ea0

We did it. Now we can run the site again and click through to our blog post and see the title and body. We don't have styles, or like ANY blog features, but we can see a list of posts and click through and read the post. If changes are made in the CMS, you'll see them on the site when you change routes.

Ready to make it fast? Check out Part 3 and see how Scully can help. You may also want to commit at this point if you haven't been doing so along the way.

< Part 1: Setting up Our Headless CMS and Azure DevOps

Part 3: Meet Scully, our Static Site Generator >