eleventy-plugin-broken-forbiden-links v1.0.1
eleventy-plugin-broken-links
This is a fork of https://github.com/bradleyburgess/eleventy-plugin-broken-links with added support for forbidden links
Table of contents
Overview
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.
Features
- 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
Dependencies
Under the hood, the plugin uses:
- node-html-parserto parse build output and gather links
- eleventy-fetchto cache results
- minimatchto handle globbing for excluded input files
- kleurfor log coloring / formatting
- valid-urlto check if it's a valid uri
Usage
1. Install the plugin
NPM:
npm i -D eleventy-plugin-broken-linksYarn:
yarn add -D eleventy-plugin-broken-links2. Add plugin to .eleventy.js config
const brokenLinksPlugin = require("eleventy-plugin-broken-links");
module.exports = (eleventyConfig) => {
  eleventyConfig.addPlugin(brokenLinksPlugin);
  // ... the rest of your config
};3. Add .cache to .gitignore
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`(4. Set options)
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) to3(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.inputvalue | Exclude input files / globs | 
| callback | null | nullor afunctionwith 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!
Options
broken, redirect and forbidden
- 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.
cacheDuration
- Default: "1d"
- Accepted: Anything accepted by eleventy-fetchplugin
Sets the cache duration for checking URL status codes. See the
eleventy-fetch plugin docs
for more info.
loggingLevel
- Default: 2
- Accepted: Integer 0to3
| Level | Result | 
|---|---|
| 0 | Silent | 
| 1 | Only log broken links | 
| 2 | Only log broken and redirect links | 
| 3 | All (verbose) | 
excludeUrls
- 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 pathsNote that the URLs specified need to be fully-qualified, so sub-domains need to be explicitly indicated.
excludeInputs
- 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.inputvalue
- Leading "dot-slash" (./) is optional, and is stripped from the input filenames andexcludeInputsvalues 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.mdGlobbing 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"callback
- Default: null
- Accepted: nullor 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:
- urlproperty
- getHttpStatusCode(), which returns the HTTP status code
- getPages()which returns an array of Eleventy- inputPathfilenames
- 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(", ")}`,
      });
    },
  });
};Roadmap / Contributing
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.
- cache results (added in v1.1.0)
- allow control over logging (added in v1.3.0)
- add option to exclude certain urls (added in v1.4.0)
- add option to exclude certain input files (added in v1.5.0)
- add debugging using debugto hook into theDEBUG=Eleventy*workflow (Added inv2.0.0)
- check internal links