npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

render-template-loader

v1.2.3

Published

A webpack loader that renders templates using one of any number of templating engines

Downloads

260

Readme

Render Template Loader

Build Status

Render templates with Webpack using one of any number of templating engines.

See The Demo Project for an example webpack project setup that uses render-template-loader with ejs to render index.html, and in the same config renders pug and handlebars templates as well.

See unit tests and webpack.config.js for other usage examples.

Built-in support for and tested with: ejs, handlebars, jade, mustache, pug, twig, and vash.

Partials support tested with ejs, handlebars, jade, twig, and pug.

Custom engine support included; see loader.spec.js.

Installation

Install render-template-loader

> npm install render-template-loader

Install a template engine or two

> npm install ejs pug

Examples

Render index.html from an ejs template

index.ejs (input)

<!doctype html>
<html lang="en">
  <head><title><%=title%></title></head>
  <body>
    <% include body %>
  </body>
</html>

body.ejs (partial)

<h1><%=title%></h1>
<h2><%=desc%></h2>

webpack.config.js (config)

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  entry: './src/index.js',
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [{
      test: /\/src\/index.ejs$/,
      use: [{
        loader: 'render-template-loader',
        options: {
          engine: 'ejs',
          locals: {
            title: 'Render Template Loader',
            desc: 'Rendering templates with a Webpack loader since 2017'
          },
          engineOptions: function (info) {
            // Ejs wants the template filename for partials rendering.
            // (Configuring a "views" option can also be done.)
            return { filename: info.filename }
          }
        }
      }]
    }]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: 'src/index.ejs'
    })
  ]
}

index.html (output)

<!doctype html>
<html lang="en">
<head><title>Render Template Loader</title></head>
<body>
  <h1>Render Template Loader</h1>
  <h2>Rendering templates with a Webpack loader since 2017</h2>

<script type="text/javascript" src="main.bundle.js"></script></body>
</html>

Render page.html from a pug template

page.pug (input)

<!doctype html>
html(lang="en")
  head
    title #{title}
  body
    include body

body.pug (partial)

<h1>#{title}</h1>
<h2>#{desc}</h2>

webpack.config.js (config)

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  entry: './src/index.js',
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [{
      test: /\.pug$/,
      use: [{
        loader: 'file-loader?name=[name].html'
      },
      {
        /**
         * We use extract-loader in this configuration because
         * file-loader above expects a string. In other configs,
         * we use HtmlWebpackLoader which handles the module
         * output of render-template-loader, so extract-loader
         * is not required.
         */
        loader: 'extract-loader'
      },
      {
        loader: 'render-template-loader',
        options: {
          engine: 'pug',
          locals: {
            title: 'Rendered with Pug!',
            desc: 'Partials Support'
          },
          engineOptions: function (info) {
            return { filename: info.filename }
          }
        }
      }]
    }]
  },
  plugins: []
}

page.html (output)

<!doctype html>
<html lang="en">
  <head><title>Rendered with Pug!</title></head>
<body>
  <h1>Rendered with Pug!</h1>
  <h2>Partials Support</h2>
</body>
</html>

Loader Options

options: {
  // The name of the engine as installed by npm (required).
  engine: 'engine name' | function (template, locals, options) {),
  // Template variables (optional).
  locals: {...} | function () { return {...} },
  // Options specific to the engine (optional).
  engingeOptions: {} | function (info) {}
  // Called before the template is rendered (optional).
  init: function (engine, info, options) {}
}

engine (string|function): (required) the name of the template engine as installed, e.g., ejs, or a custom engine function that returns the rendered template. It can’t be a arrow function because we use .call() to have webpack context as this.

engine: 'ejs',
locals: {
  title: 'Ejs Template',
  desc: 'A template rendered by ejs'
}
engine: function (input, locals, engineOptions) {
  return ejs.render(input, locals, engineOptions)
},
locals: {
  title: 'Custom Template',
  desc: 'A template rendered by a custom function (using ejs)'
}
engine: function (input, locals) {
  return input.replace(/#\{(.+?)\}/g, function (match, p1) {
    return locals[p1]
  })
},
locals: {
  title: 'Custom Template',
  desc: 'A template rendered by a custom function (using regex)'
}

locals (object): (optional) an object containing variables used by the template. A local variable title will be used by a template, e.g., <%= title %>.

locals: {
  title: 'Ejs Template',
  desc: 'A template rendered by ejs'
}

locals can also be a function that returns a locals object:

  locals: function () {
    return {
      title: 'Ejs Template',
      desc: 'A template rendered by ejs'
    }
  }
<h1><%= title %></h1>
<h2><%= desc %></h2>

engineOptions (object|function): (optional) an options object passed to the template engine when it's loaded. The content of this object is determined by each engine's configuration. For simple template rendering (without partials) engineOptions isn't usually required.

engineOptions: {
  views: ['./src/views']
}
engineOptions: function (info) {
  // The info object contains the filename of the
  // template being rendered.
  return { filename: info.filename }
}

init (function): (optional) a function called before the template is rendered. This is useful for engines that might require setup code to run before use. For instance, handlebars partials can be configured by calling handlebars.registerPartial.

engine: 'handlebars',
locals: {
  title: 'Handlebars Template',
  desc: 'A template rendered by Handlebars'
},
init: function (engine, info) {
  engine.registerPartial('description', '<h2>{{ desc }}</h2>')
}

The Loader Context

Options which can be functions have their this context set to the loader context. This allows for advanced usage, such as adding webpack dependencies on the fly. See the webpack documentation on the LoaderContext for its api methods.

Example

json data

{
  "title": "Locals as a Function with addDependency",
  "desc": "The locals function can use the loader context"
}

loader configuration

{
  loader: 'render-template-loader',
  options: {
    engine: 'ejs',
    engineOptions: function (info) {
      // Ejs wants the template filename for partials rendering.
      // (Configuring a "views" option can also be done.)
      return { filename: info.filename }
    },
    locals: function () {
      const file = path.join(__dirname, './data/locals.json')
      // Access the loader context's addDependency method to
      // add a data file dependency.
      this.addDependency(file)
      const buffer = fs.readFileSync(file)
      // Return the loaded json as the locals.
      return JSON.parse(buffer.toString())
    }
  }
}

FAQ

Why do some configurations use extract-loader and others do not?

render-template-loader exports the rendered template as a commonjs javascript module:

module.exports = "<h1>Pug Template</h1><h2>A template rendered by Pug</h2>"

In many cases, such as when using HtmlWebpackPlugin, this is exactly what you want, because module code is expected. In other cases, such as when using file-loader or html-loader or some other loader that expects plain text, extract-loader manages extracting the stirng from the module's output:

<h1>Pug Template</h1><h2>A template rendered by Pug</h2>

with extract-loader

/**
 * Use extract-loader because we're using file loader instead of
 * HtmlWebpackPlugin.
 */
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  entry: './src/index.js',
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [{
      test: /\.pug$/,
      use: [{
        loader: 'file-loader?name=[name].html'
      },
      {
        /**
         * We use extract-loader in this configuration because
         * file-loader above expects a string. In other configs,
         * we use HtmlWebpackLoader which handles the module
         * output of render-template-loader, so extract-loader
         * is not required.
         */
        loader: 'extract-loader'
      },
      {
        loader: 'render-template-loader',
        options: {
          engine: 'pug',
          locals: {
            title: 'Rendered with Pug!',
            desc: 'Partials Support'
          },
          engineOptions: function (info) {
            return { filename: info.filename }
          }
        }
      }]
    }]
  },
  plugins: []
}

without extract loader

/**
 * No need for extract-loader here because HtmlWebpackPlugin is
 * handling the index.ejs file.
 *
 */
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  entry: './src/index.js',
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [{
      test: /\/src\/index.ejs$/,
      use: [{
        loader: 'render-template-loader',
        options: {
          engine: 'ejs',
          locals: {
            title: 'Render Template Loader',
            desc: 'Rendering templates with a Webpack loader since 2017'
          },
          engineOptions: function (info) {
            // Ejs wants the template filename for partials rendering.
            // (Configuring a "views" option can also be done.)
            return { filename: info.filename }
          }
        }
      }]
    }]
  },
  plugins: [
    new HtmlWebpackPlugin({
      // Tell HtmlWebpackPlugin about our index.ejs template.
      template: 'src/index.ejs'
    })
  ]
}