Spell-checking blog posts with cSpell
Though I haven't written much on this blog, I wanted to add some basic spell-checking to my posts. I looked up "spell-checking markdown" and found an article by TJ Addison that explained how to do this with a tool called cSpell
(the backbone of the somewhat popular Code Spell Checker VS Code extension). Definitely check out TJ's article for a more in-depth explanation of cSpell
and how to use it, but here I'll explain how I set it up for my Eleventy blog.
Installing cSpell
You can use cSpell
without installing it as a dependency by running it with npx
:
npx cspell src/posts/**/*.md
But I opted for installing it permanently as a dev dependency and using an npm script to run it:
npm install cspell --save-dev
{
// ...
"scripts": {
// ...
"spell": "cspell src/posts/**/*.md"
}
}
Configuration
cSpell
allows multiple filenames for its configuration but I went with cspell.config.js
for consistency with my other config files (like eleventy.config.js
and tailwind.config.js
).
To start, set the version to 0.2
(currently always 0.2) and the language to either en
or en-GB
(both are included by default).
module.exports = {
version: '0.2',
language: 'en',
};
There are over 26 other language dictionaries available, but I'm only writing in English so I didn't need to add any others.
An important step is to define specific words to exclude or flag. I told cSpell
to ignore some 11ty-specific terminology and a few other words I use occasionally.
words: [
'eleventy',
'11ty',
'shortcodes',
'webc',
],
flagWords: [],
Dictionaries
In addition to the words
property, you can also define dictionaries - just longer lists of words. I added a dictionary for my GitHub repositories to prevent those from being spell-checked if I ever write about them.
dictionaries: ["repos"],
dictionaryDefinitions: [
{ "name": "repos", "path": "./utils/dicts/repos.txt" },
],
Instead of manually updating my repos.txt
dict, I wrote a script to fetch my repositories from the GitHub API and write them to the file.
#!/usr/bin/env node
const fs = require('node:fs/promises');
const { join } = require('node:path');
async function getRepos() {
try {
const response = await fetch(
'https://api.github.com/users/uncenter/repos',
);
const json = await response.json();
if (Array.isArray(json)) {
fs.writeFile(
join(__dirname, './dicts/repos.txt'),
json.map((repo) => repo.name).join('\n'),
);
} else {
throw new TypeError('Invalid response content.');
}
} catch {
console.error('[cspell:update] Something went wrong.');
}
}
If you're using Netlify, you can run this script and the spell-check script during the build process by adding it to the build
command in your netlify.toml
file (or the GUI on Netlify's website):
[build]
command = "node ./utils/get-repos.js && npm run spell && npm run build"
{% image "netlify-build-command.png", "Screenshot of our new build command in the Netlify GUI" %}
Ignore patterns
Finally, the config file allows you to define regular expression patterns to ignore. I added patterns to ignore words in Nunjucks expressions, Markdown code blocks and inline code, and proper nouns (words that start with a capital letter).
ignoreRegExpList: [
'nunjucksExpression',
'markdownCodeBlock',
'markdownInlineCode',
'properNouns',
],
patterns: [{% raw %}
{
name: 'nunjucksExpression',
pattern: /{%.*?%}/gis,
},
{
name: 'markdownCodeBlock',
pattern: /`{3}[\s\S]*?`{3}(?=\n|$)/gi,
},
{
name: 'markdownInlineCode',
pattern: /`[^`]*`/gi,
},
{
name: 'properNouns',
pattern: /(?<=\s|^|[^\w\s])[A-Z][a-z]+(?=\s|$|[^\w\s])/g,
},
],{% endraw %}
I'm surprised that there isn't a pattern for Markdown code blocks by default; I was having issues with common JavaScript libraries and methods being flagged as typos. Additionally, I use a few custom shortcodes that kept getting flagged as a typo, so the nunjucksExpression
pattern was a must.
Ignore words in front matter
One other neat thing about cSpell is that you can define words to ignore per file. For example, you could ignore the word supercalifragilisticexpialidocious
in just one file by adding cSpell:ignore supercalifragilisticexpialidocious
as a comment at the top of the file:
---
tags: [...]
title: Magna voluptate officia cillum Lorem proident.
description: Cupidatat excepteur ullamco laboris in veniam qui officia tempor aliquip et commodo.
date: 2000-01-01
# cSpell:ignore supercalifragilisticexpialidocious
---
You can also use spell-checker:ignore
instead of cSpell:ignore
. For more information on per document settings, see https://cspell.org/configuration/document-settings/#in-document-settings.
You don't have to put it in the front matter, but I like to keep my posts as clean & organized as possible and it looks nice there.
Let me know if you have any questions or suggestions!