I figured that with the new theme, and some more blog posts with code snippets on the way, it was time to add a syntax highlighter. For several years now, the go-to frontend recommendation has been Prism.js by Lea Verou. It’s lightweight, modular and extensible, and the syntax (ex: <pre><code class="language-xxxx">
) is both easy to add in the WordPress editor and semantically correct HTML5.
Adding the library used to be as simple as including the CSS and JS in your page template. But with modern asset bundlers like webpack, there are cleaner and leaner ways to do this, like npm’s prismjs package, which I’m going to show you how to add and get set up.
This tutorial assumes you’ve got an existing site theme being bundled with webpack. For questions about setting up your webpack.config.js
or package.json
files, check out an intro to webpack tutorial.
1. Install PrismJS via NPM
Install the Prism.js package and save it to your config.
npm install prismjs --save
Because this is package will be used client-side, make sure to use the --save
flag to ensure its added to your dependencies list, and not devDependencies. Your package.json
file should now include something like this:
{
"dependencies": {
"prismjs": "^1.15.0"
}
}
2. Install Additional NPM Prerequisites
Your webpack config is probably already loading JavaScript or some flavor of styles, unless you’re reading this in the year 2147 or something. But, while you’re checking your package.json
file, take a moment to make sure you also have style-loader
, css-loader
, and babel-loader
included in your devDependencies.
Basically, your package.json
should include the following lines:
{
"dependencies": {
"prismjs": "^1.15.0"
},
"devDependencies": {
"babel-loader": "^8.0.2",
"css-loader": "^1.0.0",
"style-loader": "^0.23.0",
"webpack": "^4.19.1"
}
}
You’ll also want to make sure your webpack.config.js
file has loaders configured for each of these packages.
3. Include PrismJS to Your Project Files
With the PrismJS package installed, and the loaders configured to include it in the bundle, we’re ready to import it using an entry point JS file. In my case I chose my article.js
entry point, because example code blocks will only appear on blog posts in my theme.
To initiate the PrismJS highlighter, create a new Prism
object in your file, and call highlightAll
on it to search the front-end markup for <pre>
and <code>
blocks with .language-xxxx
classes to highlight each them.
/* Article JS */
// Import PrismJS package
import Prism from 'prismjs';
// Highlight all matching syntax
Prism.highlightAll();
This will get the PrismJS included and working in your theme bundle so that code blocks for the basic languages (css, javascript, markup) will be parsed. However, this alone will not apply theme highlighting to the parsed blocks. To add support for additional languages and themes, you’ll need to include them from the prismjs/components
and prismjs/themes
directories. The same is true if you’re planning on importing plugins from the prismjs/plugins
directory, and you’ll need to make sure to include all necessary JS & CSS files.
At this point your entry point file will probably be looking something like this:
/* Article JS */
// Import PrismJS package
import Prism from 'prismjs';
// Import PrismJS extensions
import 'prismjs/themes/prism-twilight.css';
import 'prismjs/components/prism-scss';
// Import Prism JS
import 'prismjs/plugins/line-numbers/prism-line-numbers';
import 'prismjs/plugins/line-numbers/prism-line-numbers.css';
// Highlight all matching syntax
Prism.highlightAll();
Sure this works, but what if you’re like me and need support for “like a million” languages and plugins?
4. Install babel-plugin-prismjs to configure PrismJS
Configuring PrismJS using imports can be complicated, and its recommended that you use the babel-plugin-prismjs
to include your PrismJS options in a Babel config file.
First, remove your extension imports from the entry point JS file. (It should look like the first code snippet in step 3.)
Then, install the plugin:
npm install babel-plugin-prismjs --save-dev
The babel config file uses keys and values to build your PrismJS config. Via the documentation, these options include:
languages
: Array of languages to include in the bundle. Those languages can be found here.plugins
: Array of plugins to include in the bundle. Those plugins can be found here.theme
: Name of theme to include in the bundle. Themes can be found here.css
: Boolean indicating whether to include .css files in the result. Defaults to false. If true, imports will be added for .css files. Must be true in order for theme to work.
For example, my .babelrc
configuration for imported modules looks like this:
{
"plugins": [
["prismjs", {
"languages": [
"applescript",
"css",
"javascript",
"markup",
"scss"
],
"plugins": ["line-numbers"],
"theme": "twilight",
"css": true
}]
]
}
This config will include the language support for AppleScript and SCSS, use the twilight theme, and import a plugin to let me show line numbers. The css
value is set to true so the theme CSS will be included.
5. Testing The Results In Your Markup
You should now be ready to test highlighting code blocks in your markup. Be sure to restart your webpack build, and try adding the following markup patterns to your content:
Basic config & theme:
<pre class="language-javascript"><code>
alert('it works!');
</code></pre>
This should display JS highlighting using your theme. For example:
alert('it works!');
Additional languages:
<pre class="language-scss"><code>
$nice-blue: hsl(198, 47%, 2%);
div {
background: $nice-blue;
}
</code></pre>
This should display highlighting for SCSS, one of the additional 148 languages not supported in the core plugin. For example:
$nice-blue: hsl(198, 47%, 2%);
div {
background: $nice-blue;
}
Plugins, like line numbers:
<pre class="language-javascript line-numbers"><code>
const things = [
'Playground',
'Strategy',
'Galley',
'Mailman',
'Reference',
'Suit',
];
</code></pre>
This should display line numbers in the left column of your code preview, for example:
const things = [
'Playground',
'Strategy',
'Galley',
'Mailman',
'Reference',
'Suit',
];
6. Customizing
To override or customize styles applied by the Prism theme, you can target them in your entry point SCSS like so:
.content {
// Inline Code
code {
padding: 0 0.5em;
}
// Code Block Wrapper
pre[class*="language-"] {
background: grey;
// Code Block Contents
code {
padding: 1.5em 2em;
}
}
}
While you’re at it, you can use one of the additional themes for PrismJS, or write your own.
7. Wrapping Up
While it may seem a bit daunting at first, using npm packages to include 3rd party libraries in your bundled assets will keep your template files clean, makes it easier to control configurations, and helps limit where assets are loaded.
If you have any questions about the steps outlined here, feel free to have a look at the changes in my PR for adding PrismJS to a WordPress theme using npm packages and webpack.