Nuxt, Meet Prism
Matthew Piercey
Posted on April 14, 2020
This article is part of a series on my experiences with Nuxt.js that I built into the nuxt-toolkit by OverScore Media
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>'
})
Next, add it to your nuxt.config.js
like so:
// ...
plugins: [
{ src: '~/plugins/prism', mode: client' }
]
// ...
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>
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'
]
},
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;
}
}
Anyway, stay safe and healthy, everybody. Keep on coding!
Posted on April 14, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.