跳转到导航 跳转到主要内容
CNB版本
社区版
cnb.cool
国外版
cnb.build
2025/12/14

Custom

本页大纲
Eleventy 简称 文件扩展名 npm 包
(任意) .* (任意) (任意)

Eleventy 现在允许添加自定义模板扩展,这意味着您可以使用 Eleventy 处理任意文件扩展名并将其编译到站点的输出文件夹。此功能在 中可用。

入门示例:*.clowd

clowd 是我们刚刚创建的一个虚拟模板语言。它使用 .clowd 文件扩展名。该语言的目的是将任何出现的单词 cloud 替换为单词 butt

eleventy.config.js
export default function (eleventyConfig) {
// 添加为有效的扩展名进行处理
// 或者,将此添加到传递给 `--formats` CLI 参数的格式列表中
eleventyConfig.addTemplateFormats("clowd");

    // 这里的 "clowd" 意味着该扩展名将应用于任何 .clowd 文件
    eleventyConfig.addExtension("clowd", {
    	compile: async (inputContent) => {
    		// 将任何 cloud 实例替换为 butt
    		let output = inputContent.replace(/cloud/gi, "butt");

    		return async () => {
    			return output;
    		};
    	},
    });

};
module.exports = function (eleventyConfig) {
// 添加为有效的扩展名进行处理
// 或者,将此添加到传递给 `--formats` CLI 参数的格式列表中
eleventyConfig.addTemplateFormats("clowd");

    // 这里的 "clowd" 意味着该扩展名将应用于任何 .clowd 文件
    eleventyConfig.addExtension("clowd", {
    	compile: async (inputContent) => {
    		// 将任何 cloud 实例替换为 butt
    		let output = inputContent.replace(/cloud/gi, "butt");

    		return async () => {
    			return output;
    		};
    	},
    });

};

您可能想要使用 addExtension 但可能不应该使用的情况:

  1. 如果您想要后处理现有模板语言的内容(一个已被 Eleventy 处理的文件扩展名),请改用配置 API 转换
  2. 如果您想要使用另一个模板语言预处理 mdhtml 文件,请分别更改 Markdown 文件的默认模板引擎HTML 文件的默认模板引擎。这也可以在每个模板的基础上进行。我们可能会在未来添加更多用于预处理的钩子。

示例:为 Eleventy 添加 Sass 支持

还要注意,在上面的示例中没有使用 data。这是完整的 Eleventy 数据级联,在其他模板语言中可能更有用。

上述扩展将处理位于 subdir/test.scss 的文件,并输出到 _site/subdir/test.css 目录。

使用 inputPath

您可以传入文件的 inputPath 和 Eleventy 的 includes 文件夹,为使用 Sass 的 @use@forward@import 功能提供一组查找目录。更多关于 Sass 文档中的 loadPaths 的信息。

下面是一个完整的示例:

Filename eleventy.config.js
// 部分配置截断 …
    compile: function (inputContent, inputPath) {
      let parsed = path.parse(inputPath);

      let result = sass.compileString(inputContent, {
        loadPaths: [
          parsed.dir || ".",
          this.config.dir.includes
        ]
      });

      return (data) => {
        return result.css;
      };
    }

请特别注意上面的 this.config.dir.includes 文件夹。声明您的 includes 文件夹意味着您不需要在文件路径前添加 includes 文件夹名称(例如,_includes/_code.scss 可以用 @use "code" 来使用)。

注册依赖项

Eleventy 包含两个功能来提高自定义模板编译的性能:

  1. 编译缓存,您可以通过 compileOptions.cache 选择性地禁用
  2. 增量构建的钩子(通过 --incremental 命令行标志)

为了促进这些功能,如果模板语法允许使用其他模板(比如 Sass 中的 @use 或 WebC 中的 webc:import),Eleventy 需要知道模板文件依赖的依赖项。这在很大程度上取决于每个模板编译器。

在我们的 Sass 示例中,Sass 通过 compileString 函数的 loadedUrls 属性 暴露了这一点,您可以在下面的 compile 方法中看到我们如何注册依赖项的示例:

// 部分配置截断 …
    compile: function (inputContent, inputPath) {
      let result = sass.compileString(inputContent);

      this.addDependencies(inputPath, result.loadedUrls);

      return async (data) => {
        return result.css;
      };
    }

addDependencies 的第一个参数是父模板文件路径。第二个参数是模板使用的子文件路径数组。依赖项可以是相对路径或绝对路径,我们将根据需要对其进行规范化。

compile 函数内部跳过模板

要添加对 Sass 下划线约定的支持(以下划线开头的文件名不会写入输出目录),只需在 compile 函数中提前返回(不要返回 render 函数)。

// 部分配置截断 …
    compile: async function (inputContent, inputPath) {
      let parsed = path.parse(inputPath);
      if(parsed.name.startsWith("_")) {
        return;
      }

      let result = sass.compileString(inputContent);

      return async (data) => {
        return result.css;
      };
    }

请注意,_includes 文件夹内的文件默认被排除在处理之外,因此如果您将 sass @use@forward@import 文件存储在那里,您将免费获得此功能(参见上面的使用 inputPath 示例)!

此功能与本页后面记录的 compileOptions permalink: false 覆盖 大致相同。

为现有模板语言创建别名

如果 key 是选项对象中的唯一属性,我们将该扩展视为别名并使用现有的上游模板语法。

eleventy.config.js
export default function (eleventyConfig) {
eleventyConfig.addExtension("11ty.jsx", {
key: "11ty.js",
});

    // 或者,在 2.0.0-canary.19 或更新版本中,您可以传递扩展名数组。
    eleventyConfig.addExtension(["11ty.jsx", "11ty.ts", "11ty.tsx"], {
    	key: "11ty.js",
    });

};
module.exports = function (eleventyConfig) {
eleventyConfig.addExtension("11ty.jsx", {
key: "11ty.js",
});

    // 或者,在 2.0.0-canary.19 或更新版本中,您可以传递扩展名数组。
    eleventyConfig.addExtension(["11ty.jsx", "11ty.ts", "11ty.tsx"], {
    	key: "11ty.js",
    });

};

您可以在 TypeScriptJSXMDX 文档页面中阅读有关上述方法的信息(并查看其使用方法的更详细示例)。

key 不必是选项对象中的唯一属性。如果您想要添加自己的 compile 函数,请继续阅读

重大变更:从 Eleventy 3.0 开始,您必须将新别名添加到您声明的模板格式中,才能处理新的模板类型。

覆盖或扩展现有模板语言

您也可以覆盖或扩展现有模板语言!(感谢 Ben Holmes 的此项贡献)。

在此示例中,我们从 Eleventy 默认的 markdown-it 切换到 marked 进行 markdown 处理。

eleventy.config.js
import { marked } from "marked";

export default function (eleventyConfig) {
eleventyConfig.addExtension("md", {
compile: function (inputContent, inputPath) {
let html = marked.parse(inputContent);

    		return function (data) {
    			// 示例:仅当在数据级联中设置了 useMarked 时使用 `marked`
    			if (data.useMarked) {
    				return html;
    			}

    			// 您也可以在这里访问默认的 `markdown-it` 渲染器:
    			return this.defaultRenderer(data);
    		};
    	},
    });

};
const { marked } = require("marked");

module.exports = function (eleventyConfig) {
eleventyConfig.addExtension("md", {
compile: function (inputContent, inputPath) {
let html = marked.parse(inputContent);

    		return function (data) {
    			// 示例:仅当在数据级联中设置了 useMarked 时使用 `marked`
    			if (data.useMarked) {
    				return html;
    			}

    			// 您也可以在这里访问默认的 `markdown-it` 渲染器:
    			return this.defaultRenderer(data);
    		};
    	},
    });

};

请注意,覆盖 md 会选择退出由另一个模板语言 Markdown 文件的默认预处理。如其他地方所述,添加额外的预处理钩子的改进可能会稍后到来。

您只能覆盖模板语言一次。任何通过 addExtension 多次尝试覆盖都会抛出错误。

在选项对象中添加 key 可以解锁使用目标 defaultRenderer。您可以在 TypeScriptJSXMDX 文档页面中阅读有关此方法的信息(并查看其使用示例)(所有这些都使用 key: "11ty.js" 来扩展 JavaScript 模板)。

访问现有的过滤器和短代码

如果您想在自定义模板语言中添加对通用过滤器和短代码的支持,您可以使用以下配置 API 方法来实现。相关 GitHub #3310

  • eleventyConfig.getFilter(name)
  • eleventyConfig.getFilters()
  • eleventyConfig.getShortcode(name)
  • eleventyConfig.getShortcodes()
  • eleventyConfig.getPairedShortcode(name)
  • eleventyConfig.getPairedShortcodes()

完整选项列表

compile

  • 新文件扩展名必需别名可选。

compile 是一个支持异步的函数,接受两个参数:

  • inputContent:要解析的文件的完整内容(作为字符串)。
  • inputPath:文件的路径(作为字符串,用于查找相对导入)

compile 可以返回:

  • 无(undefined)表示应忽略该文件且不将其用作页面
  • 渲染函数(也支持异步)
// 部分配置截断 …
	compile: async (inputContent, inputPath) => {
		return async () => {
			return inputContent;
		};
	},

渲染函数被传递合并的数据对象(即模板内可用的完整数据级联)。从 compile 返回的渲染函数为每个生成的输出文件调用一次(基本模板调用一次,分页模板调用更多次)。

inputContent不包含前置内容。它将被解析、移除并插入到数据级联中。还要注意,如果 read: false(如下所述),inputContent 将是 undefined
Advanced: Adding Eleventy's Scoped Data to your Compile Function

Shortcodes and Filters both provide access to page and eleventy (via this.page and this.eleventy specifically). If you'd like to add the same for your custom template, you can do so via the augmentFunctionContext method.

compile: function(compileFn) {
		return function(data) {
			// Binds this.page and this.eleventy to your render context (and any future additions added later)
			let renderFn = eleventyConfig.augmentFunctionContext(compileFn, {
				source: data,

				// Overwrite existing values?
				// overwrite: true,

				// Lazily fetch the key using `getter`
				// lazy: false,
				// getter: (key, context) => context?.[key];
			});

			return renderFn(data);
		};
	}

outputFileExtension

  • Optional: Defaults to html

When the output file is written to the file system, what file extension should be used?

init

  • Optional

An async-friendly function that runs once (no matter how many files use the extension) for any additional setup at the beginning before any compilation or rendering.

Note that init will not re-run on watch/serve mode. If you'd like something that runs before every build, use the eleventy.before event.

// some configuration truncated …
  init: async function() {
    // has access to current configuration settings in `this.config`
  },

read

  • Optional: Defaults to true

设置为 false 来选择不从文件系统读取文件内容。如果您使用外部打包器来读取文件,这很有用。

// some configuration truncated …
  read: false,

Use with compileOptions.setCacheKey to get more fine-grained control over how the template is cached.

useLayouts

  • Optional: Defaults to true

是否将布局应用于此模板语言。这也将排除布局文件中的数据在此模板类型的数据级联中起作用。相关 GitHub #2830

useJavaScriptImport

Use the JavaScript loader instead of reading from the file system. If enabled, this takes precedence over read option.

useJavaScriptImport: true,
	getInstanceFromInputPath: async function(inputPath) {
		let mod = await import(inputPath);
		return mod.default;
	},
	compile: (compileFn) => compileFn,

getData and getInstanceFromInputPath

  • Optional

Controls if and how additional data should be retrieved from a JavaScript object to populate the Data Cascade. If your templates aren't compiling JavaScript objects, you probably won't need this.

Notably, this is separate from (in addition to) front matter parsing (which requires read: true).

// some configuration truncated …
	// `false` is the default
	getData: false, // no additional data is used
// some configuration truncated …
  getData: async function(inputPath) {
    // DIY, this object will be merged into data cascade
    return {};
  },
// some configuration truncated …
  // get the `data` property from the instance.
  getData: ["data"],
  // * `getData: true` is aliased to ["data"]
  // * You can use more than one property name! ["data", "otherPropName"]

  getInstanceFromInputPath: function(inputPath) {
    // Return the JavaScript object from which the `data` property will be retrieved.
    let instance = doSomethingMyselfToFetchAJavaScriptObject(inputPath);
    return instance;
  }
Advanced Use Case: overriding getData keys for one instance

If the JavaScript object returned from getInstanceFromInputPath has an eleventyDataKey property, this is used to override the keys returned from the getData Array for this specific instance only. Anything you can pass into a new Set() constructor works here (Array, Map, another Set).

// some configuration truncated …
  // if getData is `false`, `eleventyDataKey` will not be used.
  getData: true,

  getInstanceFromInputPath: function(inputPath) {
    return {
      // Overrides `getData` for this instance
      eleventyDataKey: ["myOverrideData"],

      // Will not be used
      data: {
        notAvailableOnGlobalData: 456
      },

      // Will be used.
      myOverrideData: {
        availableOnGlobalData: 123
      }
    }
  },

In the above example, the data cascade will include a top-level variable availableOnGlobalData with a value of 123. Using eleventyDataKey overrides any keys set in getData, which means (for this instance) data will be ignored and notAvailableOnGlobalData will not be present.

compileOptions

可选。这与 compile 函数具有相同的签名,并期望返回一个可重用的 render 函数。

// some configuration truncated …
  compileOptions: {
    permalink: function(contents, inputPath) {
      return (data) => {
        // Return a string to override: you'll want to use `data.page`
        // 或者 `return;`(返回 undefined)来回退到默认行为
      }
    }
  },
  • Don't compile permalink strings in the parent template language
    • permalink: "raw" (new default in v3.0, related GitHub #2780)
  • Don't write any files to the file system:
    • permalink: false
    • permalink: (contents, inputPath) => false
    • permalink: (contents, inputPath) => ((data) => false)
  • Override the default permalink function (return a string to override)
    • permalink: (contents, inputPath) => "…"
    • permalink: (contents, inputPath) => ((data) => "…") (use the data cascade)
    • If you return nothing (or undefined), this will revert to the default permalink behavior.

This provides another way to implement Sass' underscore convention to skip writing the file to the output directory:

Filename eleventy.config.js
// … some configuration truncated
  compileOptions: {
    permalink: function(contents, inputPath) {
      let parsed = path.parse(inputPath);
      if(parsed.name.startsWith("_")) {
        return false;
      }
    }
  },

compileOptions.spiderJavaScriptDependencies

  • Optional: Defaults to false

启用以使用 Eleventy 来爬取和监视这些模板中 require 的文件。这允许您在每个模板语言的基础上控制监视 JavaScript 依赖项功能。大多数模板语言在这里会想要默认值并保持此功能禁用。

compileOptions.cache for advanced control of caching

  • Optional: Defaults to the value of read

这控制编译步骤的缓存并保存编译的模板函数以供重用。为了更高效的清理(和长期内存使用),这些缓存现在按 inputPath 分段。

By default, whether or not this cache is enabled is tied to boolean value of read. If read: true, then cache will also be true. It's unlikely you will need this, but you can override this to mismatch read.

You can also granularly control the caching key using a getCacheKey callback. It might be useful to change this when using read: false and contents are unavailable.

If you're using 2.0.0-canary.19 or newer, you shouldn't need a getCacheKey callback. It is preferred to use the addDependencies method in the compile callback instead!
Expand to see the default getCacheKey implementation (you can override this!)
// some configuration truncated …
  read: false,
  compileOptions: {
    cache: true,
    getCacheKey: function(contents, inputPath) {
      // return contents; // this is the default in 1.0

      // return inputPath + contents; // this is the new default in 2.0.0-canary.16

      return inputPath; // override to cache by inputPath (this means the compile function will not get called when the file contents change)

      // Conditionally opt-out of cache with `return false`
      // if(someArbitraryCondition) {
      //   return false;
      // }
    }
  },

isIncrementalMatch

If you're using 2.0.0-canary.19 or newer, you shouldn't need an isIncrementalMatch callback. It is preferred to use the addDependencies method in the compile callback instead!
  • Optional

用于高级控制模板依赖项匹配的回调函数。这确定修改的文件(来自监视/服务重建)是否与每个已知完整模板文件相关。如果回调函数返回 true,模板将被渲染。如果回调函数返回 false,模板将被跳过。

Expand to see the default `isIncrementalMatch` implementation (you can override this!)
// some configuration truncated …
  // Called once for each template (matching this custom template's file extension) in your project.
  isIncrementalMatch: function(modifiedFile) {
    // is modifiedFile relevant to this.inputPath?
    if (this.isFileRelevantToInputPath) {
      // True if they are the same file
      // 或者如果它们通过任何 `addDependencies` 关系相关
      return true;
    }

    // If `modifiedFile` is not a full template (maybe an include or layout)
    // and we have no record of any dependencies for this file, we re-render everything
    if (!this.doesFileHaveDependencies && !this.isFullTemplate) {
      return true;
    }

    // Skip it
    return false;
  },

You can see more advanced override implementations in @11ty/eleventy-plugin-webc and @11ty/eleventy-plugin-vue.


其他页面在 Template Languages