Allow me to start off by saying how good and at home I feel to be able to write my blog posts using Angular with the help of Scully. And I believe most people who are looking into Scully will try to find the same feeling working on their personal blogs. In this blog, we are going to explore all the basic steps needed to get your personal blog up and running with Scully and Angular
To follow the steps in this blog post, please ensure you have the following:
AngularCLI isn't really needed because you can use
npx
First, let's create a new Angular application
npx ng new ng-scully --minimalSelect Yes for Angular Routing and whatever you are comfortable with for Stylesheet (I use SCSS).
--minimalflag tells AngularCLI to create a minimal Angular application without any files related to testings
Second, we will add Scully to our newly created Angular application. The easiest way is to use ng add schematics.
ng add @scullyio/initScully schematics will do the following:
package.json and install themScullyLibModule to AppModule'zone.js/dist/task-tracking' to polyfills.tsscully.<project_name>.config.ts to the root directory. This is Scully configuration file that we will utilize to configure Scully.
<project_name>isng-scullyin this case
Your Angular application is now Scully ready.
This is straight out of Scully documentations. Run the following schematics to add a BlogModule to our application.
ng generate @scullyio/init:blogThe above schematics will create a default BlogModule along with BlogRoutingModule under src/app/blog directory. It also updates scully.*.config.ts and AppRoutingModule to add a lazy-loaded 'blog' route to our application. Last but not least, the schematics also creates a default blog post under blog directory in the root directory.
If you do not like the default configuration, use the following schematics to customize the module name and blog directory. For the purpose of this blog post, we'll stick with the default BlogModule.
ng generate @scullyio/init:markdownThe entry page is the page when your users will land on right after they go to your website address. Scully documentations suggests to generate a HomeModule which we will follow. Feel free to adjust the following command to your liking.
ng generate module home --route=home --module=app-routingThe above command will create a HomeModule and also update AppRoutingModule to add a lazy-loaded /home route. Go ahead and change 'home' to '' since we need this to be our entry page.
// before
const routes: Routes = [
{ path: 'blog', loadChildren: () => import('./blog/blog.module').then((m) => m.BlogModule) },
{ path: 'home', loadChildren: () => import('./home/home.module').then((m) => m.HomeModule) },
];
// after
const routes: Routes = [
{ path: '', loadChildren: () => import('./home/home.module').then((m) => m.HomeModule) },
{ path: 'blog', loadChildren: () => import('./blog/blog.module').then((m) => m.BlogModule) },
];Also go to app.component.ts and clear everything in the template except for <router-outlet></router-outlet>. Now let's try to render our list of blogs in home.component.ts. Scully provides ScullyRoutesService in order to query the routes that Scully has pre-rendered.
import { Component, OnInit } from '@angular/core';
import { ScullyRoutesService } from '@scullyio/ng-lib';
import { map } from 'rxjs/operators';
@Component({
selector: 'app-home',
template: `
<ul>
<li *ngFor="let route of routes$ | async">
<a [routerLink]="[route.route]">{{ route.title }}</a>
</li>
</ul>
`,
})
export class HomeComponent {
routes$ = this.scullyRoutesService.available$.pipe(
map((routes) => routes.filter((route) => route.route.includes('/blog'))),
);
constructor(private readonly scullyRoutesService: ScullyRoutesService) {}
}What happened here? First, I removed styles: [] and ngOnInit() life-cycle since we're not using those as of this moment. Next, we inject ScullyRoutesService and use ScullyRoutesService.available$. available$ is an Observable<HandledRoute[]> which will return us all routes that have been handled by Scully. This also includes the / home route. Thus, we use map() operator to filter out the / route. The result is an Observable of all routes that have /blog in the route property.
For the template, we are just going to render a simple ul with the help of ngFor and async here. Now, the final step is to go to the blog directory and open up the single Markdown file there.
If you ran the
@scullyio/init:markdownschematics instead of the default one, please use your specified route instead of/blog. Also, your blog directory might differ fromblog
---
title: <date>-blog
description: blog description
<!-- change published to true -->
published: true
---
# <date>-blog
<date>will be whatever date the day you read this blog post.
Now, we are ready to build and see Scully in actions. Scully will read the build output of ng build and figure out which routes need to be pre-rendered based on scully.*.config.ts where right now, we only have /blog/:slug setup. This means that Scully will try to pre-render all /blog/:slug routes based on the configuration and the content in blog directory. Let's open up the terminal and run the following commands.
ng buildThis familiar command for Angular folks is needed as Scully needs the output of that command.
npm run scully
# or yarn scullyScully will start reading the build output and pre-rendering routes that it sees. It also creates a src/assets/scully-routes.json which houses the pre-rendered routes along with routes' metadata (+ frontmatter) if available. Scully's output will be under dist/static directory. Now, let's serve Scully
npm run scully:serve
# or yarn scully:serveOpen your browser and go to http://localhost:1668. You will see your HomeComponent there with a single link. Click on the link will take you to BlogComponent and your blog content (Markdown) will be rendered between the horizontal rules. Try View Page Source it and you'll see all of the pre-rendered content there which means your BlogComponent is SEO friendly. Pretty cool 👌
Even though Scully is COOL out of the box, it is still a new technology and is not without flaws. The biggest flaw in my opinon has to be Development Experience. You probably already noticed the number of commands needed to be ran to have the development server up and running. Yeah, not really convenient 🙂.
Scully documentations does not have a recommended development flow. With that said, I have the following flow that I think work pretty well for now.
npm run build when we change the component's code.npm run scully -- --watch running and keep it running. Changes to the blog content (Markdown) will trigger a re-run to scully --watch.There's still a lot of switching back and forth terminal but the above flow has been helping me tremendously. In addition, you can always set up some kind of File Watcher and run appropriate commands if you desire.
As of now, you have a working pre-rendered blog with Angular and Scully but it's pretty bland. You can:
TagComponent to render a list of blogs based on the tag.@angular/pwa to support offline mode.I'll write about all of the above points in future blog(s)
and there are tons of other stuffs to add to your blog like Newsletter, Discussion section, Google Analytics etc. Make sure to read Scully documentations. Have fun and good luck building your personal blog 👋