Home / Component Compiler

Component Compiler

What Is a Component Compiler?

When a site page is compiled, the page compiler will compile the page layout. To compile the components on the page, you need to implement component compilers for each component type.

This applies to:

Each of these components that are rendered on the page will require their own custom component compiler.

The component compiler does the same thing as the component render.mjs, but needs to run in a node application and so won’t have access to browser objects such as ‘document’ or ‘window’. They also can’t use browser-specific JavaScript libraries such as JQuery.

Create a Component Compiler

A component compiler is represented by a compile.mjs file in the ‘assets’ folder for your component. This matches the render.mjs file that you’ve created for rendering the component dynamically.

When you create a component, the default implementation of the component will automatically generate the compile.mjs file with the appropriate API.

The basic implementation is compile.mjs:

export default class {
    constructor(args) {
        this.componentId = args.componentId;
        this.SCSCompileAPI = args.SCSCompileAPI;
    }
    compile() {
        return new Promise((resolve, reject) => {
            // generate the HTML content
            const compiledHTMLContent = '';
            ...
 
            return resolve({
                content: compiledHTMLContent,
                hydrate: false
            });
        });
    }
}

Component Content

HTML

The HTML that you return from the compiler is inserted into the corresponding location within the page.

This content will typically be the same as the output created by the render() function in render.mjs. If you use a common JavaScript library that works for both node and the browser, such as Mustache, then you can also share items such as the template file between the render.mjs and compile.mjs files.

If you’re using a browser-specific JavaScript library in your render.mjs file, then you’ll need to convert the code to run under node to produce the required HTML.

CSS

Depending on your requirements, you may also need to insert CSS information into the compiled content if it can’t leverage page-level CSS resources.

JavaScript

Since the compiled content is simply HTML, itwon’t have any JavaScript event handlers, so you’ll need to either insert an additional <script> tag or use component hydration to add the event listeners or call JavaScript libraries for rendering the generated HTML into items such as carousels.

Component Hydration

If your component requires additional JavaScript to render, you can leverage the hydrate: true property in the object returned with the compiled content.

If the hydrate flag is set to true in the returned object from the compile() function, then, when the page renders at runtime, the render.js for the component will still load. However, instead of calling the render() function, it will call the hydrate() function passing in the DOM element that contains the compiled component content. This gives you the opportunity to add any event listeners or pass the compiled HTML objects to another JavaScrip library such as a carousel to update how it renders on the page.

Note: If the hydrate flag is set to false, then the render.js file for the component is not loaded at runtime. Therefore, for performance reasons, it is best to minimize the number of hydrate calls to reduce the number of runtime network requests.

Dynamic Components

The component will render dynamically at runtime if:

Therefore, you don’t need to implement all your component compilers at once as the page will continue to render correctly as you build out your component compilers.

You may also wish a component on the page to render dynamically since the data within the component changes constantly and should not be compiled statically into the page.

Use Cache to Optimize Component Compilation

If the output for a component doesn’t change from page to page or even if it does change but executes the same queries on each page, you should consider caching the results of the first run and reuse it across pages.

For example, if you have a footer component that’s the same for each page, you can cache the output and use it for subsequent pages (footer.mjs):

let footerCache;
 
export default class {
    constructor(args) {
        this.componentId = args.componentId;
        this.SCSCompileAPI = args.SCSCompileAPI;
    }
    compile() {
        footerCache = footerCache || new Promise((resolve, reject) => {
            // generate the HTML content
            const compiledHTMLContent = '';
            ...
 
            return resolve({
                content: compiledHTMLContent,
                hydrate: false
            });
        });
        return footerCache;
    }
}

You may want to have a cache “per page locale” so that as the page locale changes, you re-compile the result for the new locale. Also, keep in mind memory constraints and clean up the cache as you change locales.