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
querySelectorandquerySelectorAllto find elements using CSS-like selectors. - Attributes
getAttribute,setAttribute,removeAttribute, andupdateAttribute. TheupdateAttributemethod appends a value with a separator, which is especially useful for adding toclasslists.- DOM Manipulation
insertAdjacentHTML,appendChild,insertBefore,insertAfter,replaceWith, andremove. You can also read or replace an element's contents usinginnerHTMLandinnerText.- Node Types
- Nodes are typed as
root,tag-open,tag-close,text, orcomment. Opening and closing tags are modeled as siblings and the element's contents live in the opening tag'schildrenarray.
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;