Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

eleventy-plugin-broken-links

bradleyburgess2.1kMIT2.2.1

An Eleventy plugin to check for broken external links

11ty, 11ty-plugin, eleventy, eleventy-plugin, broken-links

readme

eleventy-plugin-broken-links

npm License: MIT Codecov

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-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

Usage

1. Install the plugin

NPM:

npm i -D eleventy-plugin-broken-links

Yarn:

yarn add -D eleventy-plugin-broken-links

2. 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) 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!


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-fetch plugin

Sets the cache duration for checking URL status codes. See the eleventy-fetch plugin docs for more info.

loggingLevel

  • Default: 2
  • Accepted: Integer 0 to 3
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 in 2.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.

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.input value
  • Leading "dot-slash" (./) is optional, and is stripped from the input filenames and excludeInputs 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"

callback

  • 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 Eleventy inputPath 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(", ")}`,
      });
    },
  });
};

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.

  • <input checked="" disabled="" type="checkbox"> cache results (added in v1.1.0)
  • <input checked="" disabled="" type="checkbox"> allow control over logging (added in v1.3.0)
  • <input checked="" disabled="" type="checkbox"> add option to exclude certain urls (added in v1.4.0)
  • <input checked="" disabled="" type="checkbox"> add option to exclude certain input files (added in v1.5.0)
  • <input checked="" disabled="" type="checkbox"> add debugging using debug to hook into the DEBUG=Eleventy* workflow (Added in v2.0.0)
  • <input disabled="" type="checkbox"> check internal links

changelog

Changelog

2.2.0 (13/14/2024)

  • Replaced Ava and Ninos with Jest

2.1.0 (04/04/2024)

  • Added option to check for forbidden links

2.0.3 (05/28/2022)

  • fixed a bug that threw an error with empty or missing href

2.0.1 (05/10/2022)

  • removed url-status-code dependency
  • fixed issue with user agent

2.0.0 (05/10/2022)

  • added debug
  • BREAKING CHANGE: added localhost to default excludeUrls

1.6.1 (04/29/2022)

  • updated docs with better example of callback
  • ensure callback only called if non-okay links

1.6.0 (04/29/2022)

  • added new callback option, which allows for custom handling of broken and redirect links on top of logging and throwing errors
    • this allows for integration with third-party services or notifications, etc.

1.5.7 (04/29/2022)

  • dropped chalk@^4 for kleur
    • later version of chalk move to ESM, which adds complication
    • kleur retains familiar syntax, while still allowing up-to-date dependencies

1.5.6 (04/28/2022)

  • refactored eleventy.after plugin for better testing
  • added tests for:
    • logger.js
    • checkLinksAndOutputResults.js
  • added GitHub workflow for Codecov
  • added Codecov badge to README

1.5.5 (04/27/2022)

  • added remaining tests
  • 100% coverage on all modules

1.5.4 (04/27/2022)

  • added AVA and NYC
  • added tests for:
    • ExternalLink class
    • getExternalLinkFromPage
    • helpers.js
    • validateUserOptions
  • fixed bug caught by tests which resulted in duplicate ExternalLink entries in store

1.5.0 (04/26/2022)

  • added validations for excludeUrls values
  • added excludeInputs feature

1.4.2 (04/25/2022)

  • fix table bug in README

1.4.1 (04/25/2022)

  • tweak README for readability and comprehensiveness

1.4.0 (04/25/2022)

  • added excludeUrls option

1.3.3 (04/25/2022)

  • refactored store as an Array for better manipulation
    • ExternalLink now includes url prop
  • refactored getExternalLinksFromPage
    • generates a new function to allow for user options, ahead of implementing exclude functionality
  • improved validations

1.3.2 (04/23/2022)

  • added note about .gitignoreing .cache to README
  • added roadmap / contributing to README

1.3.1 (04/23/2022)

  • patch redirect logging (wasn't showing url)

1.3.0 (04/23/2022)

  • implemented custom logging in separate class
  • added loggingLevel to options, allowing for control of console output:
    • 0: silent
    • 1: only broken links logged
    • 2: broken links and redirects
    • 3: all (verbose)

1.2.1 (04/23/2022)

  • patch error from empty httpStatusCode

1.2.0 (04/22/2022)

  • major refactor: ExternalLink class
  • implemented store for storing external link data
  • group URLs by link, not by page, thus checking URLs once only
  • added eslint to dev environment

1.1.0 (04/21/2022)

  • implemented cache using eleventy-fetch.
  • options now include:
    • cacheDuration to specify length of cache (based on options for eleventy-fetch)

1.0.0 (04/21/2022)

  • first working version
  • basic options:
    • broken: should broken links error or warn?
    • redirect: as above