Building a Blog with Ember (Part 2) Highlighting all the Code
In the first part of this series, we saw how to set up a new Ember application and build a file-driven blog. We generated a list of posts depending on the markdown files in our directory and parsed the file's contents using a couple of addons provided the Ember community.
So far, the markdown gets parsed to HTML and displayed as is. While this may be fine for regular text blocks, you may also want to display code from various languages and maybe even Git-diffs. To achieve this and make the code blocks look a bit nicer we are going to use a library called PrismJS, or rather the addon that implements its functionality for Ember applications.
Like with all the previous addons, we start by installing it and start the development server:
ember install ember-prism && ember serve
While the addon provides syntax highlighting for some languages, like JavaScript, out of the box, to add highlighting for Handlebars or Git some further configuration of the addon is needed. Add the following code to our application's configuration:
// ember-cli-build.js
let app = new EmberApp(defaults, {
// Add options here
'ember-prism': {
components: ['markup', 'markup-templating', 'handlebars', 'diff'],
},
})
This allows us to specify the language of a code block by adding the language to the backticks marking the start of the block, for example:
```javascript
ENV['ember-cli-markdown-resolver'] = {
folders: {
blog: 'markdown',
},
}
```
This tells Prism that the block contains JavaScript code and to highlight it accordingly.
Modify one of your markdown files like shown above and insert a code block. Now, when you visit http://localhost:4200/blog/slug-of-post-just-modified
you will see the syntax highlighting in action.
If you want to add highlighting for other languages too, you can find a list of supported Prism component on Github
And that's it! Right? Well, not quite…
Small Gotcha
If you visit a post containing a code block directly by typing its URL or refresh the page when you are on the post, you'll notice that the syntax highlighting works as expected.
However, if you navigate to a post using the link on the post listing you'll see no syntax highlighting at all. This is because Prism is — by default — only running on the initial load of the website but not re-running during navigation. Since navigating to a post renders the relevant DOM-Nodes containing the parsed markdown after the initial run of Prism, we need to manually invoke it when visiting the route.
One way to achieve this is to create a new component BlogPost
and use a lifecycle hook to invoke Prism when the component rendered. Let's do just that! First, generate the component:
ember g component blog-post
Next, use the new component on our post route. Pass in the model holding our post data as a property to the component.
// src/ui/routes/blog/post/template.hbs
-<h1>{{model.attributes.title}}</h1>
-
-<span class="post__meta">
- <span>{{model.attributes.date}}</span>
- <span>{{model.attributes.author}}</span>
-</span>
-
-{{markdown-to-html model.content}}
+<BlogPost @post={{model}} />
In our component's template, use the passed in data to display the post just like before:
// src/ui/components/blog-post/template.hbs
<h1>{{post.attributes.title}}</h1>
<span class="post__meta">
<span>{{post.attributes.date}}</span>
<span>{{post.attributes.author}}</span>
</span>
{{markdown-to-html post.content}}
Right now we still suffer from Prism not being invoked when navigating to a post. To fix that we can use the didInsertElement()
hook of our component. This hook is called once the component was initially inserted into the DOM. Let's use this to invoke Prism on our components HTML:
// src/ui/components/blog-post/component.js
import Component from '@ember/component'
export default class BlogPostComponent extends Component {
didInsertElement() {
Prism.highlightAllUnder(this.element)
}
}
And there we go! We added syntax highlighting for code blocks to our blog using yet another community addon in ember-prism.
In the next part of the series, we'll look at how to pre-render our posts during build time for improved performance and SEO friendliness.