EJS Site Builder

Generate Scripts

If you want to render several pages using the same template, specify a generate script at the end of your template.

A generator script must be a function that is either synchronous or asyncronous. When generate is called, it will be passed an object with several optional parameters which you can use in your script.

<script generate>
  (
    {
      /* Uncomment any of the following optional params to use in your generate script: */
      // require,
      // generatePages,
      // inputs,
      // getDataFileNames,
      // cache,
      // log,
      // frontMatterParse,
      // dataDir,
      // renderTemplate
    }
  ) => {
    /* Code goes here, using any of the inputs above */
    // log("example of using the supplied console log function")
  };
</script>

Description of parameters passed to your generate function

require

Allows you to import node.js compatible npm modules that you have added to your project. Use 3rd party modules at your own risk.

generatePages

A function that you call one ore more times as your page data becomes ready to render. See page generation requests for details. You can generate with an array of page requests or for a single page, one at a time. If you're rendering thousands of pages, it might be better to do it in chunks so that you don't use too much RAM, but you can also call this with all your pages at once.

inputs

getDataFileNames

A convenience function supplied by EJS Site Builder to get the absolute file names in folders relative to the data directory you specified when starting EJS Site Builder using the standard "glob" pattern matching.

Pass in a glob string or an array of glob strings and all of the matching file paths will be returned as an array.

cache

The current cache. See caching for details.

log

Call to log info to the ejssitebuilder console. This can be helpful when you want to debug your scripts.

frontMatterParse

EJS Site Builder passes an instance of frontMatterParse to your generate scripts which you can use in case you want to use front matter in your data files. This is what's happening in the following example, but is entirely optional.

dataDir

The absolute path for your data directory in case you need it for any reason.

renderTemplate (template name, template data)

EJS Site Builder allows you to render a template from within your generate script. Say you created a generate script to render some other kind of templating language, like markdown for example, but you also wanted to render your native EJS Site Builder templates as shortcodes.

In that case, you could extract the data in your generate script and pass it to one of your EJS Site Builder templates. renderTemplate expects the name of your template as the first parameter, with relative paths, and a javascript object of key value pairs specifying the data to pass into the template. See examples on on the shortcodes page. Note that calls to this function will be dependency tracked so that changes to the templates you call will trigger your generate script to run again.

Data to return (or pass to "resolve" if returning a promise)

Page Generation Request Array

You can call the generate function as many times as you want before your generate script returns or resolves asynchronously. You can call it with a single page request, or an array of them. A page generation request is an object with the following properties:

Syncronous Example:

---
generate: posts/*
---

<%= description %>

<script generate>
  ({ generatePages }) => {
    generatePages([
      {
        path: "first",
        data: {
          description: "first post",
        },
      },
      {
        path: "second",
        data: {
          description: "second post",
        },
      },
    ]);
  };
</script>

The above template will generate two posts:

└── output/posts/first
    └── index.html
└── output/posts/second
    └── index.html

Asynchrounous Example:

<script generate>
  async ({ require, generatePages, inputs, getDataFileNames }) => {
    const path = require("path");
    const fs = require("fs");
    let posts;
    if (!inputs.triggeredBy) {
      // ask for file names from the ejssitebuilder/data directory
      posts = getDataFileNames("blog/*.html"); // can use glob.
    } else {
      // if this generate function was triggered after the initial
      // render, the file which was changed will be passed here
      posts = [inputs.triggeredBy.path];
    }

    posts = posts.map((filepath) => {
      const raw = fs.readFileSync(filepath, "utf8");
      const p = path.parse(filepath);
      return {
        path: p.name,
        data: {
          title: "blog post " + p.name,
          html: raw,
        },
      };
    });

    // maybe we want post data as json to be injested by a javascript component...
    siteData = {};
    postData = [];
    posts.forEach((post) => {
      postData.push({
        path: post.path,
        title: post.title,
      });
    });
    siteData["posts/data.json"] = postData;

    // make a page for each element of posts
    generatePages(posts);

    // site files will be written
    // watchGlobs tells ejssitebuilder to monitor
    // specific folders or files for changes:
    return {
      siteFiles: siteData,
      watchGlobs: ["blog/*.html"],
    };
  };
</script>

Reusing Generate Scripts

To re-use a generate script which already exists in your project, use generate-use as follows

<script generate-use:"templateName">
</script>

A common pattern is to create a template with only the generate script specified.

You can see an example of how this works in the docs for this site:

docsMD.ejs.

The above generate script is referenced from this template: pages.ejs