Color scheme

Build Hooks

Hooks let you run your own JavaScript during the build to modify HTML before it is written to disk. Pre hooks run before template expansion and post hooks run after templates have been applied. JamsEDU also has its own built-in post hooks for things like video embedding. Your hooks are merged in and run alongside them.

Registration

To register a hook, import your function and add it to the pre or post array in your configuration file. You can register as many hooks as you need in either array.


        import myPostHook from './hooks/myPostHook.js';

        export default {
            destDir: 'www/public',
            srcDir: 'www/private',
            templateDir: 'www/private/templates',
            post: [myPostHook]
        };
    

Writing a Hook

A hook is a function that receives a scope object. This object gives you access to the parsed document tree along with information about the file being processed. Hooks do not return a value. Instead you modify scope.dom directly and JamsEDU writes the result to disk after all hooks have run.


        /**
         * @param {object} scope
         * @param {object} scope.dom - Root of the parsed document tree
         * @param {string} scope.cwd - Absolute directory of the source file
         * @param {string} scope.relPath - Path of the file relative to the project root
         */
        const myHook = (scope) => {
            const node = scope.dom.querySelector('main');
            if (node) {
                node.setAttribute('data-built', 'true');
            }
        };

        export default myHook;
    

Tree API

The document tree exposed through scope.dom is powered by simple-html-parser. It provides a familiar set of methods for querying and modifying elements.

Querying
Use querySelector and querySelectorAll to find elements using CSS-like selectors.
Attributes
getAttribute, setAttribute, removeAttribute, and updateAttribute. The updateAttribute method appends a value with a separator, which is especially useful for adding to class lists.
DOM Manipulation
insertAdjacentHTML, appendChild, insertBefore, insertAfter, replaceWith, and remove. You can also read or replace an element's contents using innerHTML and innerText.
Node Types
Nodes are typed as root, tag-open, tag-close, text, or comment. Opening and closing tags are modeled as siblings and the element's contents live in the opening tag's children array.

For the full API reference see the simple-html-parser repository on GitHub.

Example

This post hook finds all video elements with a src attribute and replaces each one with a responsive figure wrapping an iframe embed.


        const replaceVideos = (scope) => {
            const videoNodes = scope.dom.querySelectorAll('video[src]');

            for (const videoNode of videoNodes) {
                const url = videoNode.getAttribute('src');
                const html = `<figure class="video"><iframe src="${url}"></iframe></figure>`;
                videoNode.insertAdjacentHTML('beforebegin', html);
                videoNode.remove();
            }
        };

        export default replaceVideos;