@unic/estatico-handlebars v0.0.11
@unic/estatico-handlebars
Transforms Handlebars to HTML.
Installation
$ npm install --save-dev @unic/estatico-handlebarsUsage
const gulp = require('gulp');
const path = require('path');
const env = require('minimist')(process.argv.slice(2));
/**
 * HTML task
 * Transforms Handlebars to HTML
 *
 * Using `--watch` (or manually setting `env` to `{ watch: true }`) starts file watcher
 * When combined with `--skipBuild`, the task will not run immediately but only after changes
 *
 * Using `-LLLL` will display debug info like the data used for every template
 */
gulp.task('html', () => {
  const task = require('@unic/estatico-handlebars');
  const estaticoWatch = require('@unic/estatico-watch');
  const { readFileSyncCached } = require('@unic/estatico-utils');
  const instance = task({
    src: [
      './src/*.hbs',
      './src/pages/**/*.hbs',
      './src/demo/pages/**/*.hbs',
      '!./src/demo/pages/handlebars/*.hbs',
      './src/modules/**/!(_)*.hbs',
      './src/demo/modules/**/!(_)*.hbs',
      './src/preview/styleguide/*.hbs',
      '!./src/preview/styleguide/colors.hbs',
    ],
    srcBase: './src',
    dest: './dist',
    watch: {
      src: [
        './src/**/*.hbs',
        './src/**/*.data.js',
      ],
      name: 'html',
      dependencyGraph: {
        srcBase: './',
        resolver: {
          hbs: {
            match: /{{(?:>|#extend)[\s-]*["|']?([^"\s(]+).*?}}/g,
            resolve: (match /* , filePath */) => {
              if (!match[1]) {
                return null;
              }
              let resolvedPath = path.resolve('./src', match[1]);
              // Add extension
              resolvedPath = `${resolvedPath}.hbs`;
              return resolvedPath;
            },
          },
          js: {
            match: /require\('(.*?\.data\.js)'\)/g,
            resolve: (match, filePath) => {
              if (!match[1]) {
                return null;
              }
              return path.resolve(path.dirname(filePath), match[1]);
            },
          },
        },
      },
      watcher: estaticoWatch,
    },
    plugins: {
      clone: null,
      handlebars: {
        partials: [
          './src/**/*.hbs',
        ],
      },
      // Wrap with module layout
      transformBefore: (file) => {
        if (file.path.match(/(\\|\/)modules(\\|\/)/)) {
          return Buffer.from(readFileSyncCached('./src/preview/layouts/module.hbs'));
        }
        return file.contents;
      },
      // Relativify absolute paths
      transformAfter: (file) => {
        let content = file.contents.toString();
        let relPathPrefix = path.join(path.relative(file.path, './src'));
        relPathPrefix = relPathPrefix
          .replace(new RegExp(`\\${path.sep}g`), '/') // Normalize path separator
          .replace(/\.\.$/, ''); // Remove trailing ..
        content = content.replace(/('|")\/(?!\^)/g, `$1${relPathPrefix}`);
        content = Buffer.from(content);
        return content;
      },
    },
  }, env);
  
  // Don't immediately run task when skipping build
  if (env.watch && env.skipBuild) {
    return instance;
  }
  return instance();
});Run task (assuming the project's package.json specifies "scripts": { "gulp": "gulp" }):
$ npm run gulp html
See possible flags specified above.
API
plugin(options, env) => taskFn
options
src (required)
Type: Array or String
Default: null
Passed to gulp.src.
srcBase (required)
Type: String
Default: null
Passed as base option to gulp.src.
dest (required)
Type: String
Default: null
Passed to gulp.dest.
watch
Type: Object
Default: null
Passed to file watcher when --watch is used.
plugins
Type: Object
plugins.handlebars
Type: Object
Default:
handlebars: {
  partials: null,
  helpers: null, // NOTE: handlebars-layouts are registered by default
}Passed to gulp-hb.
Partials and helpers are resolved via handlebars-wax. This is happening outside of the task function, allowing us to export the handlebars instance with partials and helpers already registered. It can be required via require('@unic/estatico-handlebars').handlebars.
A simple helper example:
{
  helpers: {
    link: object => `<a href="${object.url}">${object.text}</a>`,
    foo: bar => `<span>${bar}</span>`,
  },
}If a helpers needs access to handlebars, a factory has to be used instead (see docs on handlebars-wax):
{
  helpers: {
    register: (handlebars) => {
      handlebars.registerHelper('link', (object) => { // eslint-disable-line arrow-body-style
        return new handlebars.SafeString(`<a href="${object.url}">${object.text}</a>`);
      });
      handlebars.registerHelper('foo', bar => `<span>${bar}</span>`);
    },
  },
}NOTE: handlebars-layouts) is registered by default
plugins.data
Type: Function
Default:
data: (file) => {
  // Find .data.js file with same name
  try {
    const data = require(file.path.replace(path.extname(file.path), '.data.js'));
    return Object.assign({}, data);
  } catch (e) {
    return {};
  }
}Setting up data to be used in handlebars compiling. Return value will be assigned to file.data where gulp-hb picks it up.
plugins.prettify
Type: Object
Default:
prettify: {
  indent_with_tabs: false,
  max_preserve_newlines: 1,
}Passed to gulp-prettify. Setting to null will disable this step.
plugins.clone
Type: Object
Default:
clone: dev ? null : {
  data: {
    env: {
      dev: false,
    },
  },
  rename: filePath => filePath.replace(path.extname(filePath), `.prod${path.extname(filePath)}`),
},This potentially speeds up CI builds (where the same templates are built with both a dev and prod config) since we only run the expensive task of setting up the data once.
The CI needs to take care of moving & renaming the .prod.html files.
logger
Type: { info: Function, debug: Function, error: Function }
Default: Instance of estatico-utils's Logger utility.
Set of logger utility functions used within the task.
env
Type: Object
Default: {}
Result from parsing CLI arguments via minimist, e.g. { dev: true, watch: true }. Some defaults are affected by this, see above.
License
Apache 2.0.