Nuxt, Prismic and PrismJS

Friday, June 14th @ 5:36 pm CDT

A few weeks ago I started playing with Nuxt and Prismic to build a new statically generated site as my blog. I was able to jump over the first hurdle of just getting it up and running 🚀with a big thanks to Francesco Michelini's article which can be found here. As with most developers writing these things, I wanted to eventually hook in some nifty syntax highlighting for my code examples.

Since PrismJS manipulates the DOM when you use it in the typical way, and because Vue is already doing its own DOM manipulation they are basically at odds with one another. Luckily, PrismJS does provide the highlight function which can be passed any string of text to mark up. Alright so we can just pass it the code example text!

Wait... our code examples are embedded in the text we pull in from Prismic to build our blog 🤦🏻‍♂️So here's what we need to do to mark up the code:

  • Keep the markup included in the blog post data from Prismic
  • Mark up only the code example text using PrismJS
  • Replace the non-highlighted code example text with the highlighted code example text

Enough Already, Show Me How to Do It!

You can see the code for all of this on my Github. Here's some notes on the applicable code.

First, you'll need PrismJS:

npm i -P prismjs

Then, we can add some code. First, let's setup a custom plugin for PrismJS. It's pretty easy.

plugins/prism.js

import 'prismjs'
import 'prismjs/components/prism-bash'
import 'prismjs/components/prism-typescript'
// Other languages can be added here
import 'prismjs/themes/prism-solarizedlight.css'

We just import PrismJS, then any languages we'll be using, and a theme of your choosing. Next, let's add a helper method that will replace our code examples in the data we receive from Prismic with the "prismified" version. You can put this file anywhere, but I keep it in a file called formatting.js in the helpers folder. I've added some comments inline to help understand what's going on.

helpers/formatting.js

import PrismicDOM from 'prismic-dom'
import Prism from 'prismjs'

export const prismify = data => {
  let richText = PrismicDOM.RichText.asHtml(data)
  // Find all instances of <pre class="language-SOME_LANGUAGE">SOME_CONTENT</pre>
  const toReplace = richText.match(
    /<pre\sclass="language-(?:\w*)">(.*?(?=<\/pre>))<\/pre>/gs
  )

  // Keep track of which match index is being replaced
  let replaceIndex = 0

  data.forEach(docSection => {
    if (docSection.type === 'preformatted') {
      // Use label from Prismic to determine language for PrismJS
      const codeLanguage = docSection.label.replace('language-', '')
      richText = richText.replace(
        toReplace[replaceIndex],
        // Include <pre> and <code> tags as per best practices
        `<pre class="language-${codeLanguage}"><code class="language-${codeLanguage}">` +
          // Throw in the highlighted marked-up code
          Prism.highlight(
            docSection.text,
            Prism.languages[codeLanguage],
            codeLanguage
          ) +
          '</code></pre>'
      )
      // Move to the next replaceIndex for the next preformatted block found
      replaceIndex++
    }
  })
  // Profit!
  return richText
}

Now, wherever you need to ensure that data from Prismic is marked up using PrismJS, just pass the data through this prismify helper function and you're all set!

Just to reiterate - what you'll do in Prismic is write code examples in a preformatted block, then apply a tag with the format language-typescript or language-bash or whichever language you're writing in to the preformatted block in order for this to work. Their UI can be a bit hard to read when you apply tags to preformatted blocks, so I use a custom stylesheet using the Stylebot extension in Chrome to overcome this.

Voila

And there you have it, beautiful syntax highlighting by PrismJS in your Nuxt app pulling its data from Prismic. I hope this article has helped you in reaching some of your goals in learning Nuxt!