DEV Community

Matthew Piercey for OverScore Media

Posted on • Edited on

Nuxt, Meet Prism

This article is part of a series on my experiences with Nuxt.js that I built into the nuxt-toolkit by OverScore Media

GitHub logo overscore-media / nuxt-toolkit

A bunch of useful example code snippets for use with Nuxt.js

See a live example at https://nuxt-toolkit.overscore.media! :]


Ah, syntax highlighting. The beauty of code made manifest!

Syntax highlighting can make or break a site in terms of UI, IMO, since all too often I see nasty or downright-broken code blocks on websites that should frankly know better... But every now and then there's something of such pure magic that it makes it all worth it.

There are a bunch of ways of getting syntax highlighting to work with JavaScript. This is one way of many, but it's the way I did it. Take that as you will.

Look into the Prism

Prism is my favourite syntax highlighting library. It's really quite nice when you get it all set up. Admittedly, to get it to work the way I like it, I ended up importing a bunch of CSS and quite a bit of JS that I probably didn't end up needing, and which definitely added to my Nuxt project's bundle size considerably (and it's an absolute nightmare to try to make it play nice with things like PurgeCSS), but... Tradeoffs? I mean, would you rather have a slightly-slower-but-still-fairly-zippy site that looks beautiful or a super-fast site that looks "meh"? I don't know. Fight about it in the comments, I guess? _(ツ)_/¯

Ready?

If you are ready to start, and you want to do it my way for some reason, first import the libraries you'll need to make it happen.

yarn add prismjs clipboard or npm install --save prismjs clipboard

Next, bundle it all up in a Nuxt plugin, like ~/plugins/prism.js. Choose your own Prism theme, language supports, and plugins. Fair warning, there are a lot of them from which to choose. You might be here for a while...

/* eslint-disable no-template-curly-in-string */
/* eslint-disable no-undef */
import 'clipboard' // For the copy to clipboard plugin
import Prism from 'prismjs'
import Vue from 'vue'

// Include a theme:
import 'prismjs/themes/prism-tomorrow.css'

// Include language support: (optional)
import 'prismjs/components/prism-scss'
import 'prismjs/components/prism-markup'
import 'prismjs/components/prism-ruby'

// Include the toolbar plugin: (optional)
import 'prismjs/plugins/toolbar/prism-toolbar'
import 'prismjs/plugins/toolbar/prism-toolbar.css'

// Include the autolinker plugin: (optional)
import 'prismjs/plugins/autolinker/prism-autolinker'
import 'prismjs/plugins/autolinker/prism-autolinker.css'

// Include the line numbers plugin: (optional)
import 'prismjs/plugins/line-numbers/prism-line-numbers'
import 'prismjs/plugins/line-numbers/prism-line-numbers.css'

// Include the line highlight plugin: (optional)
import 'prismjs/plugins/line-highlight/prism-line-highlight'
import 'prismjs/plugins/line-highlight/prism-line-highlight.css'

// Include some other plugins: (optional)
import 'prismjs/plugins/copy-to-clipboard/prism-copy-to-clipboard'
import 'prismjs/plugins/highlight-keywords/prism-highlight-keywords'
import 'prismjs/plugins/show-language/prism-show-language'
import 'prismjs/plugins/normalize-whitespace/prism-normalize-whitespace'

Vue.component('prism', {
  props: {
    lang: {
      type: String,
      default: 'js'
    }
  },
  mounted () {
    Prism.highlightAll()
  },
  template: '<div class="prism"><pre class="line-numbers" :class="`language-${lang}`"><code><slot></slot></code></pre></div>'
})
Enter fullscreen mode Exit fullscreen mode

Next, add it to your nuxt.config.js like so:

// ...
plugins: [
  { src: '~/plugins/prism', mode: client' }
]
// ...
Enter fullscreen mode Exit fullscreen mode

Use it for realsies

Try out something like this to make sure it works:

<prism lang="scss">
.VueToNuxtLogo {
  display: inline-block;
  animation: turn 2s linear forwards 1s;
  transform: rotateX(180deg);
  position: relative;
  overflow: hidden;
  height: 180px;
  width: 245px;
}
</prism>
Enter fullscreen mode Exit fullscreen mode

Caveat(s)

Fair warning - if you're using this to display HTML or any sort of XML-y markup, you may run into issues if you don't put escaped markup inside the <prism> block. Try converting your markup to escaped markup with an online converter or something.

Also, PurgeCSS and Prism don't like each other all that much, so if you happen to be using them together, prepare to have your wonderful styling ripped away by Purge's unrelenting scourge, all in the name of bundle size reduction... Granted, there is probably a ton of unused CSS if you happen to do it this way, but Purge is overly-aggressive. Now, you can add some words to your PurgeCSS whitelist, but honestly it's a mess and I haven't figured out a better solution, and you'll probably have to manually add classes to make things work... Or just don't use Purge (or don't do it this way). Your call. Either way, almost every solution causes new problems, so you can't really avoid making these difficult choices if you want to have some nice things.

  purgeCSS: {
    enabled: true, // True means it's always on in dev/build/generate mode
    // The two below options achieve the happy medium between Prism.js and PurgeCSS
    // If you're having trouble with code highlighting, try adding the pertinent clases to the whitelist
    whitelistPatternsChildren: [/token$/],
    whitelist: [
      'pre', 'code', 'prism', 'line-numbers', 'tag', 'toolbar-item', 'toolbar',
      'code-toolbar', 'span', 'button', 'line-numbers-rows', 'url-link', 'attr-name', 'attr-value', 'punctuation',
      'keyword', 'keyword-let', 'operator', 'string'
    ]
  },
Enter fullscreen mode Exit fullscreen mode

Also, if you're using Vuetify, this code will remove some of the default styling so your code blocks don't look weird:

code {
  box-shadow: 0 !important;
  &::before {
    content: '' !important;
  }
}
Enter fullscreen mode Exit fullscreen mode

Anyway, stay safe and healthy, everybody. Keep on coding!

Top comments (4)

Collapse
 
tomrichter profile image
Tom Richter

Unfortunately this isn't working for me. I get this instead: "[Vue warn]: You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build." Does anybody have an idea what is missing? Thanks!

Collapse
 
ilrock__ profile image
Andrea Rocca 👨‍🍳

Hey Matthew, thanks for sharing this. I was actually looking into adding Prism to my Gridsome website today and this post saved me a lot of digging through their docs. Cheers!

Collapse
 
mtpiercey profile image
Matthew Piercey

Nice! Yep, it's a jungle out there... Glad I was able to help; good luck with Gridsome!

Collapse
 
ismailonly profile image
ismailonly

Wonderful :)
Can you please show how to use Prism to make an editor to enter code.