This is an 11ty plugin to check for broken external links after a build.
Currently it only checks external links, but checking internal links might be added at some point.
- caching using
eleventy-fetch
- excluding URLs
- control of level of logging
- warn or error on broken, redirected or forbidden links
- exclude certain URLs or wildcards
- exclude certain input files or globs
Under the hood, the plugin uses:
-
node-html-parser
to parse build output and gather links -
eleventy-fetch
to cache results -
minimatch
to handle globbing for excluded input files -
kleur
for log coloring / formatting -
valid-url
to check if it's a valid uri
NPM:
npm i -D eleventy-plugin-broken-links
Yarn:
yarn add -D eleventy-plugin-broken-links
const brokenLinksPlugin = require("eleventy-plugin-broken-links");
module.exports = (eleventyConfig) => {
eleventyConfig.addPlugin(brokenLinksPlugin);
// ... the rest of your config
};
See this privacy notice in the eleventy-fetch
docs
about why we should ignore the .cache
directory. Unless you really know
what you're doing, it's probably a good idea.
.cache/
# ... the rest of your `.gitignore`
There are currently 7 possible keys to the optional options
object passed
with eleventyConfig.addPlugin()
:
Option | Default | Accepted values | Description |
---|---|---|---|
forbidden |
"warn" |
"warn" , "error"
|
Whether to warn or throw an error |
broken |
"warn" |
"warn" , "error"
|
(same as above) |
redirect |
"warn" |
"warn" , "error"
|
(same as above) |
cacheDuration |
"1d" |
any value accepted by eleventy-fetch
|
Set the duration of the cache |
loggingLevel |
2 |
Integer 0 (silent) to 3 (all) |
Set the logging level |
excludeUrls |
['http://localhost*', 'https://localhost*'] |
Array of URL strings | Exclude specific URLs or wildcards |
excludeInputs |
[] |
Array of globs, relative to eleventyConfig.dir.input value
|
Exclude input files / globs |
callback |
null |
null or a function with signature (brokenLinks, redirectLinks) => {}
|
Custom callback after checking links |
Here's an example using all options, with the defaults:
const brokenLinksPlugin = require("eleventy-plugin-broken-links");
module.exports = (eleventyConfig) => {
// ... the rest of your config
eleventyConfig.addPlugin(brokenLinksPlugin, {
forbidden: "warn",
redirect: "warn",
broken: "warn",
cacheDuration: "1d",
loggingLevel: 2,
excludeUrls: [],
excludeInputs: [],
callback: null,
});
};
NOTE: If the broken
, redirect
or forbidden
options are set to error
, your
build will not be successful if there are broken/redirected links!
- Default:
"warn"
- Accepted:
"warn"
or"error"
Whether to warn
or error
if broken, redirect or forbidden links are found. If error
,
builds will not succeed if any are found.
- Default:
"1d"
- Accepted: Anything accepted by
eleventy-fetch
plugin
Sets the cache duration for checking URL status codes. See the
eleventy-fetch
plugin docs
for more info.
- Default:
2
- Accepted: Integer
0
to3
Level | Result |
---|---|
0 |
Silent |
1 |
Only log broken links |
2 |
Only log broken and redirect links |
3 |
All (verbose) |
-
Default:
['http://localhost*', 'https://localhost*']
(new in2.0.0
) - Accepted: Array of URL strings
You can exclude specific URLs by specifying their fully-qualified uri:
excludeUrls: ["https://example.com"];
But you can also use a wildcard (*
) to exclude domains or sub-paths. Examples:
"https://example.com"; // excludes only the root URL,
// but sub-paths will be include,
// e.g. 'https://example.com/about'
"https://example.com/about"; // excludes only '/about', but root and other
// pages are included
"https://example.com/about/*"; // excludes any path nested under 'about',
// but includes 'about'
"https://example.com/about*"; // excludes any sub-path that begins
// with `about`, INCLUDING all nested paths
"https://example.com/*"; // excludes all paths, but includes the root
"https://example.com*"; // excludes the root and all paths
Note that the URLs specified need to be fully-qualified, so sub-domains need to be explicitly indicated.
- Default:
[]
- Accepted: Array of files or globs, relative to
dir.input
You can exclude specific input files by providing an array of files or globs.
Please note:
- All files and globs are relative to the config
dir.input
value - Leading "dot-slash" (
./
) is optional, and is stripped from the input filenames andexcludeInputs
values when normalized before processing
To illustrate these points:
// - `dir.input` not set in config (`undefined`)
["index.md"]["./index.md"][ // exclude only ./index.md // identical to above
// - `dir.input` = "src":
"index.md"
]; // exclude ./src/index.md
Globbing is handled by minimatch
under the hood. Some examples:
// Some globbing examples:
["**/index.md"]["**/*.md"]["notes/**"]["**/./*.md"]["**/+(foo|bar).md"]; // exclude all index.md files recursively // exclude all .md files recursively // exclude all files recursively in 'notes' // exclude all .md files in subdirectories only // exclude all files named "foo.md" or "bar.md"
- Default:
null
- Accepted:
null
or a function with signature(brokenLinks, redirectLinks, forbiddenLinks) => {}
Custom callback for handling broken, redirect or forbidden links after checking and
logging results (and before throwing an error, if option is set). The three
arguments, brokenLinks
, redirectLinks
and forbiddenLinks
are arrays of instances of the
ExternalLink
class,
which has the following methods and properties:
-
url
property -
getHttpStatusCode()
, which returns the HTTP status code -
getPages()
which returns an array of EleventyinputPath
filenames -
getLinkCount()
, which returns the number of times the link is used in the site's pages
This allows for integration with third-party services, webhooks, etc. Here's a basic example:
// your project's .eleventy.js:
const thirdPartyService = require("service");
const brokenLinksPlugin = require("eleventy-plugin-broken-links");
module.exports = (eleventyConfig) => {
eleventyConfig.addPlugin(brokenLinksPlugin, {
callback: (brokenLinks, redirectLinks) => {
thirdPartyService.post({
msg: `Your eleventy build had broken links! Links: ${brokenLinks.map(link => link.url).join(", ")}`,
});
},
});
};
I don't have a specific roadmap or timeline for this project, but here is a general idea of what the next steps are. If you would like to contribute, please feel free to file an issue or feature request, or send a PR.
- [x] cache results (added in
v1.1.0
) - [x] allow control over logging (added in
v1.3.0
) - [x] add option to exclude certain urls (added in
v1.4.0
) - [x] add option to exclude certain input files (added in
v1.5.0
) - [x] add debugging using
debug
to hook into theDEBUG=Eleventy*
workflow (Added inv2.0.0
) - [ ] check internal links