创建插件

创建你自己的插件来扩展 Lume 的指南

Lume 可以通过添加更多 loaders, engines, processors 等来轻松扩展。插件提供了一个简单的接口,用于扩展 Lume,而无需在 _config.ts 文件中编写太多代码。

插件只是一个函数,它在第一个参数中接收一个 lume 实例,以便配置和注册新的元素。

简单的插件示例

假设我们在 _config.ts 文件中有以下代码,用于向所有 CSS 页面添加版权横幅:

// _config.ts

import lume from "lume/mod.ts";

const site = lume();

function addBanner(content: string): string {
  const banner = "/* © This code belongs to ACME inc. */";
  return banner + "\n" + content;
}

site.process([".css"], (pages) => {
  for (const page of pages) {
    page.content = addBanner(page.content as string);
  }
});

export default site;

我们可以将这段代码封装在一个插件中,甚至可以包含一些配置:

// my-plugins/css_banner.ts

interface Options {
  message: string;
}

export default function (options: Options) {
  function addBanner(content: string): string {
    const banner = `/* ${options.message} */`;
    return banner + "\n" + content;
  }

  return (site: Site) => {
    site.process([".css"], (pages) => {
      for (const page of pages) {
        page.content = addBanner(page.content as string);
      }
    });
  };
}

现在,我们可以通过这种方式在 _config.ts 文件中使用它:

import lume from "lume/mod.ts";
import cssBanner from "./my-plugins/css_banner.ts";

const site = lume();

site.use(cssBanner({
  message: "© This code belongs to ACME inc.",
}));

export default site;

插件不能做任何你在 _config.ts 文件中做不到的事情,但它们提供了一个更好的接口来组织和重用你的代码。更好的是:与他人分享它。

查看 Lume 插件仓库 获取更高级的示例。

Hooks

一些插件公开 hooks,这些 hooks 可以被其他插件或在 _config.ts 文件中调用。Hook 只是一个函数,它可以做任何事情,例如更改插件的配置。Hooks 存储在 site.hooks 中。让我们在 css_banner 插件中创建一个 hook 来更改消息:

// my-plugins/css_banner.ts

interface Options {
  message: string;
}

export default function (options: Options) {
  function addBanner(content: string): string {
    const banner = `/* ${options.message} */`;
    return banner + "\n" + content;
  }

  return (site: Site) => {
    // 添加一个 hook 来更改消息
    site.hooks.changeCssBanner = (message: string) => {
      options.message = message;
    };

    site.process([".css"], (page) => {
      page.content = addBanner(page.content as string);
    });
  };
}

现在可以在插件安装后更改消息:

import lume from "lume/mod.ts";
import cssBanner from "./my-plugins/css_banner.ts";

const site = lume();

site.use(cssBanner({
  message: "© This code belongs to ACME inc.",
}));

site.hooks.changeCssBanner("This code is open source");

export default site;

或者我们可以从其他插件调用这个 hook:

// my-plugins/open_source.ts

export default function () {
  return (site: Site) => {
    if (!site.hooks.changeCssBanner) {
      throw new Error("This plugin requires css_banner to be installed before");
      // 此插件需要先安装 css_banner
    }

    site.hooks.changeCssBanner("This code is open source");
  };
}
import lume from "lume/mod.ts";
import cssBanner from "./my-plugins/css_banner.ts";
import openSource from "./my-plugins/open_source.ts";

const site = lume();

site.use(cssBanner({
  message: "© This code belongs to ACME inc.",
}));

site.use(openSource());

export default site;

发布插件

如果你创建了一个插件并想让其他人使用它,由于 HTTP 导入和 Deno 原生的 TypeScript 支持,这非常简单。你只需要通过 HTTP URL 使你的代码可访问。

这是一些建议列表:

  • 使用 lume/ 标识符从 Lume 导入模块。例如,假设你的插件使用 merge 工具函数。而不是像这样导入完整的 URL:
import { merge } from "https://deno.land/x/lume@v2.2.0/core/utils/object.ts";

最好使用 lume/ 标识符:

import { merge } from "lume/core/utils/object.ts";

这避免了项目中加载的 Lume 版本重复,因为 lume/ 标识符在 import maps 中配置(记住在你的 import maps 中包含此条目)。

  • 使用 HTTP 包注册表,例如 deno.land/x。或者,你可以使用 jsDelivr 从 GitHub 仓库提供文件并确保可靠性(即使 GitHub 仓库被删除,它们也会被永久缓存 even if the GitHub repository is deleted)。

  • 不推荐使用 JSR,因为它不支持 HTTP 导入(无法导入 Lume 类型),有 bug 的 import maps 行为,以及平台自动进行的代码更改,这些更改可能会导致意外的 bug。

  • 一旦你的插件发布,请告诉我们!!你可以创建一个 PR 到 awesome-lume 仓库