Archetypes

Scripts to create a templates for new content.

Archetypes are scripts that edit or create new files in your source directory with some preconfigured content. A typical example are posts on a blog: instead of creating a markdown file from scratch every time you want to create a new post, you can create and run an archetype to do this job for you.

Archetypes in Lume are JavaScript or TypeScript files, stored in the _archetypes directory that default export a function returning the configuration of the file that is going to be created. For example:

// _archetypes/example.js

export default function () {
  return {
    path: "/pages/example.md",
    content: "Content of the file",
  };
}

This archetype creates the file /pages/example.md inside your src directory with the content Content of the file. The archetype filename is example.js, so the name of the archetype is example. To execute it just run npx @lumeland/lume run example.

Running archetypes

As you can see, to run an archetype, just run npx @lumeland/lume run [archetype_name]. The archetype name is the file name (without extension) and Lume will search that file in the _archetypes directory, inside the src folder.

It's possible to run other archetypes using a relative path. In this case you need to include the path of the file including the extension. For example:

npx @lumeland/lume run ./my-templates/new-post.ts

Content

The content variable can be a string, a Uint8Array (for binary files) an object or an URL. If the content is an object, it will be converted to a string depending on the extension of the path:

  • If the path has the yml or yaml extension, the object will be stringified as YAML.
  • If the path has the json extension, the object will be stringified as JSON.
  • For other extensions, the object will be converted to frontmatter + text.

This is an example of YAML conversion:

export default function () {
  return {
    path: "/pages/example.yml",
    content: {
      title: "Title content",
      content: "Page content",
    },
  };
}
title: Title content
content: Page content

Same example, but for JSON conversion:

export default function () {
  return {
    path: "/pages/example.json",
    content: {
      title: "Title content",
      content: "Page content",
    },
  };
}
{
  "title": "Title content",
  "content": "Page content",
}

Same example, but for any other extension (for example, md):

export default function () {
  return {
    path: "/pages/example.md",
    content: {
      title: "Title content",
      content: "Page content",
    },
  };
}
---
title: Title content
---

Page content

If the content is in instance of URL, the file will be downloaded. For example:

export default function () {
  return {
    path: "/avatar.png",
    content: new URL("https://example.com/avatar.png"),
  };
}

Passing arguments

Arguments allow passing variables to the archetype to configure how the new content is created. For example, if we want to create new pages based on the provided title:

// _archetypes/page.ts

export default function (title: string) {
  const slug = title.replace(/\s+/g, "-").toLowerCase();

  return {
    path: `/pages/${slug}.md`,
    content: {
      title: title,
      content: "Page content",
    },
  };
}

This function uses the title argument to generate the final path and the content. Now you can run pnx lume run page "My first page", and the new /pages/my-first-page.md file will be created. Any extra arguments passed to the CLI command will be passed to the archetype's function.

Multiple files

It's possible to generate multiple files from the same archetype. To do that, use a generator to yield all files. In the following example, the archetype creates a new section in the site with several pages and a _data.yml file:

// _archetypes/section.ts

export default function* (title: string) {
  const slug = title.replace(/\s+/g, "-").toLowerCase();

  // Create the shared data
  yield {
    path: `/pages/${slug}/_data.yml`,
    content: {
      layout: "section.vto",
      section_title: title,
    },
  };

  // Create 3 more pages
  const pages = [1, 2, 3];
  for (const page of pages) {
    yield {
      path: `/pages/${slug}/${page}.md`,
      content: {
        title: `Page ${page}`,
        content: "Write the content here",
      },
    };
  }
}

As you can see, Lume's archetypes are simple but flexible and powerful. And because they are just plain JavaScript/TypeScript files, it's possible to reuse them. For example, you can create an archetype that imports other archetypes.

base option

By default, the paths of the generated files are relative to the src folder. Use the property base to change the base path to the root folder (the same folder where the _config.ts is.

export default function () {
  return {
    path: "example.txt",
    base: "root",
    content: "Content of the file",
  };
}

Edit existing files

Archetypes can be used to edit existing files. To do that, use a function in the content property. Lume will execute this function passing the existing content in the first argument. For example, to edit the package.json file to change the version:

export default function () {
  return {
    path: "package.json",
    base: "root", // to save the file in the root directory instead of src
    content(json) {
      json.version = "0.0.0";
      return json;
    },
  };
}

When running this archetype, the package.json file is read, and the parsed JSON is passed to the content function. If the file doesn't exist, the argument is undefined.

Built-in archetypes

Lume provides the following archetypes out of the box:

  • npx lume run new-plugin: Creates the boilerplate code for a custom plugin in the _plugins folder
  • npx lume run new-archetype: Creates the boilerplate code for a custom archetype in the _archetypes folder.

Defining archetypes in the _config file

Instead of using the _archetypes folder, it's possible to add new archetypes in the _config.ts using the site.archetype() function. This is useful for plugins or themes to register their own archetypes.

// Use a file path or URL
site.archetype("post", "_archetypes/post.ts");

// Use a function:
site.archetype("post", () => {
  const name = prompt("Name of the post");
  return {
    path: `/posts/${name}.md`,
    content: "Start typing...",
  };
});

Run npx lume run post and the archetype is executed.