eleventy-load Lightning

Writing a loader

An eleventy-load loader is just a JavaScript function, nothing complicated! The function is passed two arguments: the content of the file being loaded and the user-provided options for the loader.

An example loader #

Let’s write a loader to convert a text file to uppercase, but only if the user passes uppercase: true as an option. Of course, this loader could be applied to any file, it just uppercases the content.

module.exports = function (eleventyConfig) {
  eleventyConfig.addPlugin(require("eleventy-load"), {
    rules: [
      {
        test: /\.txt$/,
        loaders: [
          {
            loader: function (content, options) {
              return options.uppercase ? content.toUpperCase() : content;
            },
            options: {
              uppercase: true,
            },
          },
        ],
      },
    ],
  });
};

Instead of writing the loader in your Eleventy configuration file, you might want to move it into a module which exports the loader function.

module.exports = function (content, options) {
  return options.uppercase ? content.toUpperCase() : content;
};
const uppercaseLoader = require("./uppercase");

module.exports = function (eleventyConfig) {
  eleventyConfig.addPlugin(require("eleventy-load"), {
    rules: [
      {
        test: /\.txt$/,
        loaders: [
          {
            loader: uppercaseLoader,
            options: {
              uppercase: true,
            },
          },
        ],
      },
    ],
  });
};

Loader interface #

As well as the function parameters content and options, loaders also have access to the loader context. The context of a function can be accessed using the this keyword.

this.addDependency #

Add a dependency to be processed by eleventy-load. The dependency must be relative to the Eleventy project’s input directory. You should always await adding a dependency, as the loaders processing the dependency might be asynchronous.

module.exports = async function (content, options) {
  const license = await this.addDependency("LICENSE");
  return license + content;
};

this.config #

A copy of the Eleventy configuration object passed to plugins, with two added properties: inputDir and outputDir.

{
  "inputDir": "src",
  "outputDir": "dist"
}
Click to see a full example of this.config generated by eleventy-load.
{
  "inputDir": "src",
  "outputDir": "dist",
  "events": {
    "_events": {},
    "_eventsCount": 1
  },
  "collections": {},
  "liquidOptions": {
    "dynamicPartials": true
  },
  "liquidTags": {},
  "liquidFilters": {},
  "liquidShortcodes": {},
  "liquidPairedShortcodes": {},
  "nunjucksFilters": {},
  "nunjucksAsyncFilters": {},
  "nunjucksTags": {},
  "nunjucksShortcodes": {},
  "nunjucksAsyncShortcodes": {},
  "nunjucksPairedShortcodes": {},
  "nunjucksAsyncPairedShortcodes": {},
  "handlebarsHelpers": {},
  "handlebarsShortcodes": {},
  "handlebarsPairedShortcodes": {},
  "javascriptFunctions": {},
  "pugOptions": {},
  "ejsOptions": {},
  "markdownHighlighter": null,
  "libraryOverrides": {},
  "passthroughCopies": {},
  "layoutAliases": {},
  "linters": {},
  "filters": {},
  "activeNamespace": "",
  "dynamicPermalinks": true,
  "useGitIgnore": true,
  "dataDeepMerge": true,
  "extensionMap": {},
  "watchJavaScriptDependencies": true,
  "additionalWatchTargets": [
    "./src/"
  ],
  "browserSyncConfig": {},
  "chokidarConfig": {},
  "watchThrottleWaitTime": 0,
  "dataExtensions": {},
  "quietMode": false
}

this.emitFile #

Save content to a file in the project’s output directory. The function takes three parameters:

  1. The content to save, either a String or Buffer.
  2. The filepath in which to save the content, relative to the project’s output directory.
  3. A flag which dictates whether the file should be saved. Defaults to true, pass false to dry run.
module.exports = async function (content, options) {
  return this.emitFile(content, "assets/[name].[hash:12].css", false);
};

The filepath can contain placeholders, useful for creating hashed files. The following placeholders are replaced:

this.resource #

The current resource being processed, relative to the project’s input directory. Use this.resourcePath and this.resourceQuery to access the path and the query respectively.

module.exports = function (content, options) {
  console.log(this.resource); // assets/cat.jpeg?width=1920&height=1080&format=webp
};

this.resourcePath #

The path of the current resource being processed, relative to the project’s input directory. Here’s an example which gets the last-modified time of the current resource.

const fs = require("fs");
const path = require("path");

module.exports = function (content, options) {
  console.log(this.resourcePath); // assets/cat.jpeg
  const resource = path.resolve(this.config.inputDir, this.resourcePath);
  const lastModifiedTime = fs.statSync(resource).mtime;
};

this.resourceQuery #

The query of the current resource being processed. You can use URLSearchParams to easily parse the query.

module.exports = function (content, options) {
  console.log(this.resourceQuery); // ?width=1920&height=1080&format=webp
  const params = new URLSearchParams(this.resourceQuery);
  console.log(params.get("format")); // webp
};

Raw loaders #

By default, the content of a resource is loaded as a UTF-8 string and passed to the first loader. By setting the raw flag to true, the loader will receive a raw Buffer instead of a String. This is useful for loaders which deal with binary filetypes, such as images.

module.exports = function (content, options) {
  console.log(content instanceof Buffer); // true
};

module.exports.raw = true;