Extensions

You can add extensions to customize the behavior of myst.

To add extensions, specify in the extension to myst.json:

myst.json
{
  "outDir": "./out",
  "rootDir": "./src",
  "data": "./data",
  "dependency": ["./templates"],
  "extension": "./extensions/foo.js"
}

Extensions should export a function that takes RenderContext as a single argument.

Using RenderContext, you can add hooks.

RenderContext#addPostLoadDataHook

Using addPostLoadDataHook, you can modify data loaded from data directory after it is loaded.

It is useful when you want to do some calculations from data. You can access the data by context.data.

Example

data/numbers.js
// This will be available as context.data.numbers
module.exports = [1, 2, 3, 4, 5];
extensions/foo.js
module.exports = (context)=>{
    context.addPostLoadDataHook((context)=>{
        context.data.sum = context.data.numbers.reduce((a,b)=>a+b);
    });
};

RenderContext#addPreRenderHook

By preRenderHook, you can modify the data passed to template engines before each file is rendered.

The difference from addPostLoadDataHook is that this hook is processed for each files and that modification does not affect rendering of other files.

extensions/foo.js
module.exports = (context)=>{
    context.addPreRenderHook((context, filename, data)=>{
        // filename is an absolute path of the file being rendered
        // It is safe to directly modify the data:
        data.filename = path.basename(filename);
    });
};

RenderContext#addPostRenderHook

Using addPostRenderHook, you can modify the result of renderers.

For example, following extension minifies every HTML file using html-minifier.

extensions/foo.js
const minify = require('html-minifier').minify;
module.exports = (context)=>{
    context.addPostRenderHook((context, content, target)=>{
        if (!/\.html$/.test(target)){
            return content;
        }
        return minify(content, {
            collapseWhitespace: true,
        });
    });
};

addPostRenderHook takes a callback function as an argument. context is current RenderContext. content is result of renderers in string. target is an absolute path of output file.

Note that if you do not want to modify content, you must return context as-is, instead of returning null or others. Returning null cancels rendering current target.

RenderContext#addUnknownExtensionHook

You can handle any filename extension you want by using addUnknownExtensionHook.

You have to somehow make RenderFunction to define how to handle files. my-static exports renderUtil. To just copy files to output folder:

extensions/foo.js
const myst = require('my-static');
module.exports = (context)=>{
    context.addUnknownExtensionHook((context, ext)=>{
        if (ext === '.csv'){
            return myst.renderUtil.makeStaticRenderer(context);
        }
        return null;
    });
};

RenderContext#addLoadFileHook

Using addLoadFileHook, you can replace the procedure of loading rendered files.

extensions/foo.js
module.exports = (context)=>{
    context.addLoadFileHook((context, filename, binary)=>{
        // `binary` is a boolean flag. If true, Buffer is expected. Otherwise, string is expected.
        // Return raw data or Promise.
        // By returning null, you can fallback to next hook (or default procedure).
        if (path.extname(filename) === '.txt'){
            return 'I am txt file ^o^';
        }
        return null;
    });
};

RenderContext#addPostLoadFileHook

Using addPostLoadFileHook, you can modify the content of the rendered file before it is passed to template engines.

extensions/foo.js
module.exports = (context)=>{
    context.addPostLoadFileHook((context, filename, data)=>{
        // Data loaded by my-static is passed as the third argument.
        // Return raw data or Promise.
        // Return null to leave it untouched.
        return null;
    });
};