lib/renderer/template.js
- /**
- * Methods for rendering a template.
- */
- import _ from 'lodash';
- import nunjucks from 'nunjucks';
- import moment from 'moment';
- import Url from '../url';
-
- const TemplateErrorMessage = {
- NO_TEMPLATE: 'template not found',
- };
-
- /**
- * Render a template with given context variables.
- * @param {Object} env Nunjucks instance;
- * @param {string} template Template name, excluding the extension.
- * @param {object} variables Object of variables to interpolate in the
- * template.
- * @return {string} Rendered template.
- */
- export function renderTemplate(env, template, variables) {
- if (!env) {
- return '';
- }
-
- let result = '';
- try {
- result = env.render(`${template}.html`, variables);
- } catch (e) {
- if (e.message.includes(TemplateErrorMessage.NO_TEMPLATE)) {
- // The message given from nunjucks looks like:
- // Template render error: (/reptar/templates/page.html)
- // Template render error: (/reptar/templates/page.html)
- // Error: template not found: mistake.html
- // This takes the multi line message and just grabs the last line.
- const message = _.last(e.message.split('\n'))
- .trim()
- // Format the last line of `Error: template` to remove anything
- // preceding our known error message. (Basically remove `Error: `)
- .replace(
- new RegExp(`.*${TemplateErrorMessage.NO_TEMPLATE}`),
- TemplateErrorMessage.NO_TEMPLATE
- );
-
- // Re-throw formatted error message.
- throw new Error(message);
- } else {
- throw e;
- }
- }
-
- return result;
- }
-
- /**
- * Render a string template with given context variables.
- * @param {Object} env Nunjucks instance;
- * @param {string} str Template string.
- * @param {object} variables Object of variables to interpolate in the
- * template.
- * @return {string} Rendered template.
- */
- export function renderTemplateString(env, str, variables) {
- if (!env) {
- return '';
- }
-
- return env.renderString(str, variables);
- }
-
- /**
- * Allow adding custom filters to the template engine.
- * @see {@link http://mozilla.github.io/nunjucks/api#custom-filters}
- * @param {Object} env Nunjucks instance;
- * @param {string} name Filter name.
- * @param {Function} func Filter function.
- * @param {boolean} async Whether the filter should be async.
- */
- export function addTemplateFilter(env, name, func, async = false) {
- env.addFilter(name, func, async);
- }
-
- /**
- * Adds built in filters to template renderer.
- * @param {Object} env Nunjucks instance;
- * @param {Object} config Config instance.
- */
- function addBuiltinFilters(env, config) {
- function dateFilter(date, momentTemplate) {
- if (date == null) {
- return '';
- }
-
- return moment
- .utc(date, config.get('file.dateFormat'))
- .format(momentTemplate);
- }
-
- [
- ['date', dateFilter],
- [
- 'groupbydate',
- // Group items by formating their date via momentjs.
- // Useful for creating archive pages:
- // eslint-disable-next-line
- // {% for date, files in collections.post.files | reverse | groupbydate('MMMM YYYY') %}
- function groupbydate(data, momentTemplate, dateKey = 'date') {
- return _.groupBy(data, datum =>
- dateFilter(datum[dateKey], momentTemplate)
- );
- },
- ],
- [
- 'slug',
- function slug(str) {
- return Url.slug(str);
- },
- ],
- [
- 'absolute_url',
- function absoluteUrl(relativePath, basePath) {
- let base = basePath || '';
- const baseLength = base.length - 1;
- base = base[baseLength] === '/' ? base.substr(0, baseLength) : base;
-
- let input = relativePath || '';
- const inputLength = input.length - 1;
- if (input[inputLength] !== '/') {
- input = `${input}/`;
- }
- if (input[0] !== '/') {
- input = `/${input}`;
- }
-
- return base + input;
- },
- ],
- [
- 'limit',
- function limit(arr, length) {
- return arr.slice(0, length);
- },
- ],
- ].forEach(filter => {
- addTemplateFilter(env, ...filter);
- });
- }
-
- /**
- * Exposed method to configure template engine.
- * @param {Object} options Options object with following properties:
- * @param {Object} options.config Config object.
- * @param {string|Array.<string>} options.paths Either an array of paths or a
- * singular path that we can load templates from.
- * @param {boolean} options.noCache Whether our template engine should cache
- * its templates. Only set to true when in watch mode.
- * @return {Object} Nunjucks instance.
- */
- export function configureTemplateEngine({ config, paths, noCache = false }) {
- const fileSystemLoader = new nunjucks.FileSystemLoader(paths, {
- noCache,
- });
-
- const env = new nunjucks.Environment(fileSystemLoader, {
- autoescape: false,
- });
-
- addBuiltinFilters(env, config);
-
- return env;
- }