Add a blog to your Angular website using markdown files

Last week I wanted to add a blog to my Angular Universal website, but I didn’t wanted to implement a complex solution and spend to much time on it. Neither did I wanted to add a CMS or even store the articles in a database. That’s why I came up, I think, with a pretty handy, for not saying dumb simple, solution with the implementation of a blog based on markdown files 🚀

Before going further: If you are looking to implement a blog, you are looking to share your stories but you are also most probably looking to make your website more SEO friendly. Therefore, I assume that you already have implemented an Angular SSR website. If not, I would really advise you to have a look to that particular topic and if you do have, don’t miss the very last chapter of this article, a kind of hack is needed in order to load the resources correctly on the backend side

Installation

npm install ngx-markdown --save

Content

  • assets > blog > blog.md: the list of blog entries
  • assets > blog > post > *.md: the articles (= blog posts) themselves

Routes

  • A route “/blog” which will display a list of all articles
  • A route “/blog/post/name-of-the-article” which will display a particular blog post. In this route example the blog post name is “name-of-the-article”

I did group all routes under the same “blog” path, therefore the structure will look like the following once implemented

Implementation

@NgModule({
imports: [
CommonModule,
RouterModule.forChild([
{path: '', pathMatch: 'full', loadChildren: './blog/blog-view.module#BlogViewModule'},
{path: 'post', loadChildren: './post/blog-post-view.module#BlogPostViewModule'},
]),
MarkdownModule.forRoot()
]
})

Blog

@NgModule({
declarations: [BlogViewComponent],
imports: [
CommonModule,
RouterModule.forChild([
{ path: '', component: BlogViewComponent}
]),
ComponentsModule,
MarkdownModule.forChild()
]
})

Finally, we could add a markdown directive to our template blog-view.component.html which will automatically load and display the content of the markdown file, told you it’s super easy 😂

<div markdown [src]="'./assets/blog/blog.md'"></div>

As you could notice, the directive reference the blog.md file which just consists of the list of entries (one title, subtitle and author per blog post) and relative urls which will be used for the navigation

##  [Title](/blog/post/name-of-the-article)
### [Subtitle](/blog/post/
name-of-the-article)
Posted by [David](mailto:david@fluster.io) on September 6, 2018

Post

@NgModule({
declarations: [BlogPostViewComponent],
imports: [
CommonModule,
RouterModule.forChild([
{ path: '', component: BlogPostViewComponent},
{ path: ':id', component: BlogPostViewComponent, pathMatch: 'full'}
]),
ComponentsModule,
MarkdownModule.forChild()
]
})

Once done, we could again add the directive to our template, this time we are not going to reference a particular file but rather use a variable name post

<div markdown [src]="post"></div>

I guess you understood, since we are using a route parameter, we have to initialize this variable using the interface ActivatedRoute

@Component({
selector: 'app-blog-post-view',
styleUrls: ['./blog-post-view.component.scss'],
templateUrl: './blog-post-view.component.html'
})
export class BlogPostViewComponent implements OnInit, OnDestroy {

private sub: Subscription;

post: string;

constructor(private route: ActivatedRoute) {

}

ngOnInit() {
this.sub = this.route.params.subscribe(params => {
this.post = './assets/blog/post/' + params['id'] + '.md';
});
}

ngOnDestroy() {
if (this.sub) {
this.sub.unsubscribe();
}
}

}

Et voilà, that’s it, nothing more nothing left in order to route, load and display our blog 👍

Of course the solution would probably need a bit of styling, I won’t cover that in this article but if you are using Bootstrap you could for example have a look to this free clean blog theme

Once implemented and styled our blog could look like the one I have implemented 👉 https://fluster.io/blog

Cherry on the cake 🍒🎂

Bonus hack 🤖

In order to help our Angular Universal server to load correctly the resources we need for ngx-markdown, the idea is to intercept all Http requests with the goal to rewrite them with an understandable server side host path. Not rocket science but definitely a must have for our implementation of a friendly SEO blog based on markdown files

import {Inject, Injectable, PLATFORM_ID} from '@angular/core';
import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http';

import {isPlatformServer} from '@angular/common';

import {Observable} from 'rxjs'

@Injectable({
providedIn: 'root'
})
export class HttpInterceptorService implements HttpInterceptor {

constructor(@Inject(PLATFORM_ID) private platformId: Object) {
}

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (isPlatformServer(this.platformId) && req.url.includes('./')) {
return next.handle(req.clone({
url: `http://localhost:8000/${req.url.replace('./', '')}`
}));
}

return next.handle(req);
}
}

Have fun blogging 🤓
David

Freelancer by day | Creator of DeckDeckGo by night | Organizer of the Ionic and IndieHackers Zürich Meetup

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store