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

simple-nunjucks-loader

v3.2.0

Published

Webpack loader for Nunjucks

Downloads

8,453

Readme

npm package Coverage Status node Build Status Dependencies Status

Nunjucks templates loader for Webpack

This Webpack loader compiles Nunjucks templates. html-webpack-plugin compatible.

For Webpack 4 support use loader 2.x version

Install

npm install --save-dev simple-nunjucks-loader

If you don't use dynamic assets in your code, then you could save a bit on optional glob dependency:

npm install --no-optional --save-dev simple-nunjucks-loader

Usage

This loader will precompile Nunjucks templates. It also includes Nunjunks (slim) runtime for browser.

Add loader to your webpack config as follows:

webpack.config.js

module.exports = {
    module: {
        rules: [
            {
                test: /\.njk$/,
                use: [
                    {
                        loader: 'simple-nunjucks-loader',
                        options: {}
                    }
                ]
            }
        ]
    }
};

template.njk

<p>Hello, {{ username }}!</p>

index.js

import template from './template.njk'

document.body.innerHTML = template({
  username: 'Mike'
})

Bundling of index.js above will render paragraph with text "Hello, Mike!" to the page.

More examples on loader site.

How it works

By default Nunjunks bundle all precompiled templates to window.nunjucksPrecompiled, then loads them via custom loader from this global object. If precompiled template reference some other template file, it is loaded from disk (in NodeJS environment), or fetched via XMLHttpRequest from internet and precompile downloaded template in runtime.

Both are not webpack-way for projects bundling.

This loader got template source, parse it with Nunjucks parser, to get AST of template. This AST is iterated to get info on imported templates, used filters and extensions.

Next step is precompile template, to make it faster. Loader injects own wrapper to avoid default behaviour with creating global window.nunjucksPrecompiled.

One final step is gather all parts together. Loader is inserts imports of templates, filters and extensions that somehow noted in template, this will make Webpack to rebuild template only when one of essential part is changed.

Then loader expose module that will create separate environment with only required filters and extensions. This module is what you invoke to get your template rendered.

Assets support

Loader add own {% static %} tag, for loading assets, and track their change.

Signature is same to static tag from Django.

template.njk

<img alt="" src="{% static 'image.jpg' %}" />

See more examples of setup and using assets in loader.

Asynchronous support

When loader found async tags or async filters or extensions in the template, it calls render with callback under the hood, and returns Promise, instead of render result.

Because of asynchronous nature of Webpack assets loading, all assets, that loaded via {% static %} tag, make template to return Promise too.

Options

Loader supports limited number of Nunjuncks options. It's doesn't support watch (we use webpack own dependencies watch), noCache, web settings and express.

All other options get passed to Nunjunks Environment during files loading.

|Name|Type|Default|Description| |:--:|:--:|:-----:|:----------| |jinjaCompat|{Boolean}|false|Install Jinja syntax support in bundle| |searchPaths|{String} or {Array.<string>}|.|One or more paths to resolve templates paths| |assetsPaths|{String} or {Array.<string>}|.|Paths to resolve static assets. Works like STATICFILES_DIRS.| |globals|Object.<string, string>|{}|Map global function to corresponding module| |extensions|Object.<string, string>|{}|Map extension to corresponding module| |filters|Object.<string, string>|{}|Map filters to corresponding module| |autoescape|{Boolean}|true|See Nunjuncks options for description of options below| |throwOnUndefined|{Boolean}|false|| |trimBlocks|{Boolean}|false|| |lstripBlocks|{Boolean}|false|| |tags|{Object.<string, string>}|Default Jinja tags config|Override tags syntax| |dev|{Boolean}|true for development and false for production mode|Undocumented Nunjucks option, that will make stacktraces more useful|

tags default to:

{
    blockStart: '{%',
    blockEnd: '%}',
    variableStart: '{{',
    variableEnd: '}}',
    commentStart: '{#',
    commentEnd: '#}'
}

jinjaCompat

Installs Jinja syntax. This option install it for whole bundle.

searchPaths

Loader is searching for full template relative to given string(s) from searchPath option (or project root, if no paths given).

Path to file couldn't be outside of folders above.

webpack.config.js

module.exports = {
    module: {
        rules: [
            {
                test: /\.njk$/,
                use: [{
                    loader: 'simple-nunjucks-loader',
                    options: {
                        searchPaths: [
                            'django_app_a/templates',
                            'django_app_b/templates'
                        ]
                    }
                }]
            }
        ]
    }
};

assetsPaths

List of paths where loader should search for assets.

module.exports = {
    module: {
        rules: [
            {
                test: /\.njk$/,
                use: [{
                    loader: 'simple-nunjucks-loader',
                    options: {
                        assetsPaths: [
                            'django_app_a/static',
                            'django_app_b/static'
                        ]
                    }
                }]
            }
        ]
    }
};

globals

Set global function and import path, that should return function to use. It the same function that env.addGlobal using.

webpack.config.js

module.exports = {
    module: {
        rules: [
            {
                test: /\.njk$/,
                use: [{
                    loader: 'simple-nunjucks-loader',
                    options: {
                        globals: {
                            _: 'lodash',
                            globalFn: path.join(__dirname, 'global-fn.js')
                        }
                    }
                }]
            }
        ]
    }
};

global-fn.js

module.exports = function globalFn(foo, bar) {
    return `Do anything with ${foo} and ${bar}`;
};

extensions

Set map of extensions that would be imported before each template render. Extension should return instance, that would be added via env.addExtension.

webpack.config.js

module.exports = {
    module: {
        rules: [
            {
                test: /\.njk$/,
                use: [{
                    loader: 'simple-nunjucks-loader',
                    options: {
                        extensions: {
                            CustomExtension: path.join(__dirname, 'extension.js')
                        }
                    }
                }]
            }
        ]
    }
};

:boom: Using ES modules syntax for extensions is not yet possible

extension.js

// You should use slim bundle to make it work in browser
const nunjucks = require('nunjucks/browser/nunjucks-slim');

// See example in docs
// https://mozilla.github.io/nunjucks/api.html#custom-tags
class CustomExtension {}

module.exports = new CustomExtension();

Loader trying to guess which extensions are really used, and keep only required imports.

filters

Map of filters, that would be imported before each template render. Filter should return instance, that would be added via env.addFilter.

webpack.config.js

module.exports = {
    module: {
        rules: [
            {
                test: /\.njk$/,
                use: [{
                    loader: 'simple-nunjucks-loader',
                    options: {
                        filters: {
                            filter: path.join(__dirname, 'filter.js')
                        }
                    }
                }]
            }
        ]
    }
};

:boom: Using ES modules syntax for filters is not yet possible

filter.js

module.exports = function filter(val, param) {
    return `${val + param}`;
};

template.njk

{{ foo_var | filter(3) }}

Nunjucks is not aware that filter is asynchronous when parse template to AST. Because of that, you should mark filter as async. To do that, filter module should export async flag:

async-filter.js

function asyncFilter(val, param, callback) {
    setTimeout(function() {
        callback(null, val + param);
    }, 1000);
}

asyncFilter.async = true;

module.exports = asyncFilter;