Coder Social home page Coder Social logo

chocolateboy / parcel-plugin-nunjucks Goto Github PK

View Code? Open in Web Editor NEW
50.0 3.0 8.0 2.3 MB

Parcel support for nunjucks templates

License: MIT License

JavaScript 83.82% Nunjucks 16.18%
parcel parcel-plugin nunjucks template templates parcel-bundler plugin

parcel-plugin-nunjucks's Introduction

parcel-plugin-nunjucks

Build Status NPM Version

NAME

parcel-plugin-nunjucks - Parcel support for nunjucks templates

INSTALLATION

$ npm install nunjucks # peer dependency
$ npm install parcel-plugin-nunjucks

SYNOPSIS

$ cat src/html/index.njk
{% extends 'layout.njk' %}

{% block body %}
    <h1>Hello, {{ name }}!</h1>
{% endblock %}
$ cat nunjucks.config.js
module.exports = {
    root: './src/html',
    data: { name: process.env.USER },
}
$ parcel build src/html/index.njk

DESCRIPTION

This is a Parcel plugin which uses nunjucks to translate templates with an .njk extension into Parcel assets.

As with other asset types, nunjucks templates can be top-level entries, or dependencies referenced from other documents or templates.

CONFIGURATION

An environment for any (or every) nunjucks template known to Parcel can be configured by creating a nunjucks entry in the project's package.json file, or by exporting (CommonJS) or defining (JSON) a configuration object in one of the following files:

  • .nunjucksrc (JSON)
  • .nunjucks.js
  • nunjucks.config.js

Type

The configuration object has the following type:

interface AssetType {
    value?: false | string;
    raw?: boolean;
}

interface NunjucksConfiguration {
    assetType?: false | string | AssetType | ((path: Path) => (false | string | AssetType));
    data?:      object | ((path: Path) => (object | PromiseLike<object>));
    env?:       Nunjucks.Environment | ((path: Path) => Nunjucks.Environment);
    filters?:   { [name: string]: Function };
    options?:   Nunjucks.ConfigureOptions;
    root?:      string | string[];
}

Path parameter

Options that are defined as functions (assetType, data, and env) are passed an object containing the parsed components of the template's absolute path (including the path itself) as a parameter, e.g. if the path is /foo/bar/baz.html.njk, the parameter would contain the following fields:

{
    baseExt:  '.html',
    basePath: '/foo/bar/baz.html',
    dir:      '/foo/bar',
    dirname:  'bar',
    dirs:     ['', 'foo', 'bar'],
    ext:      '.njk',
    filename: 'baz.html.njk',
    name:     'baz.html',
    path:     '/foo/bar/baz.html.njk',
    root:     '/',
}

Options

The following options can be defined.

assetType

Override a template's type within Parcel. This allows the rendered template to be processed as a file of the specified type, e.g. a HTML template will be scanned for links to scripts, stylesheets etc., and a templated JavaScript file will be scanned for requires and imports etc.

Defined as a falsey value (the default), a string, or an object, or can be defined as a function, in which case it is called with an object containing the path of the template being processed (see Path parameter), and its return value is used as the asset type.

By default, each template's type is determined by the extension before the .njk suffix, defaulting to HTML if there isn't one or if the extension isn't recognized, e.g.:

filename type
index.html.njk HTML
index.js.njk JavaScript
index.css.njk CSS
index.njk HTML
page-1.0.njk HTML

This behavior can be overridden by setting the assetType option. The default value is falsey, which enables the filename-matching behavior. Setting it to a string makes the value the type for all .njk files, e.g. setting it to html makes all files HTML regardless of the filename (which was the default in parcel-plugin-nunjucks v1):

module.exports = {
    data: { ... },
    assetType: 'html',
}

The supported types are the extensions registered with Parcel, including those registered by plugins, and they typically correspond to the standard extensions for the respective filetypes, e.g.:

extension type
css CSS
htm/html HTML
js JavaScript
ts TypeScript

The type can be written with or without the leading dot, e.g. html and .html are equivalent.

As an example, the following configuration assigns the default type(s) to most files, but overrides the type for files in src/js and src/css. This allows the latter to be output as e.g. foo.html, bar.js, baz.css etc. rather than foo.html.html, bar.js.js, baz.css.css etc.

// if there's no base extension, infer the asset type from the name of the
// containing directory, e.g.:
//
//   - foo.html.njk    → html
//   - bar.js.njk      → js
//   - baz.css.njk     → css
//   - src/js/foo.njk  → js
//   - src/css/bar.njk → css
//
module.exports = {
    assetType ({ baseExt, dirname }) {
        return baseExt || dirname
    }
}

Raw assets

By default, nunjucks assets are processed as the specified or inferred asset-type i.e. they're scanned and transformed in the same way as regular JavaScript/HTML etc. files. In some cases, it may be preferable to specify a rendered template's target type/extension (e.g. HTML) without processing it as that type (e.g. with PostHTML). This can be done by supplying the assetType option as an object rather than a string, and setting its raw property to true, e.g.:

module.exports = {
    data: { ... },
    assetType: { value: 'html', raw: true },
}

If not supplied, the raw property defaults to false. As with the non-object shorthand, the value property can be falsey (infer the type from the filename) or a type name (string), e.g. html or .js.

data

Data to expose as the "context" in nunjucks assets. Can be defined as a function, in which case it is called with an object containing the path of the template being processed (see Path parameter), and its return value (which can be a promise if the data is loaded asynchronously) is used as the data.

module.exports = {
    data: { name: process.env.USER }
}

// or

async function getData ({ filename }) {
    const data = await http.getData()
    return { filename, ...data }
}

module.exports = { data: getData }

env

The Environment instance to use. Can be defined as a function, in which case it is called with an object containing the path of the template being processed (see Path parameter), and its return value is used as the environment.

const Nunjucks = require('nunjucks')
const env = Nunjucks.configure('./src/html')

env.addFilter('uc', value => value.toUpperCase())

module.exports = { env }

filters

A map (object) of name/function pairs to add as filters to the environment. Ignored if the env option is supplied.

module.exports = {
    filters: {
        uc: value => value.toUpperCase(),
        lc: value => value.toLowerCase(),
    }
}

options

Options to pass to the nunjucks#configure method, which is used to construct the Environment instance. Ignored if the env option is supplied.

module.exports = {
    options: { autoescape: false }
}

root

The base template directory or directories. Can be a single path (string) or multiple paths (array of strings). If not supplied, it defaults to the current directory (.). Ignored if the env option is supplied.

Relative paths are resolved against the directory of the configuration file in which the paths are defined (or the package.json if defined there), falling back to the current working directory if a configuration file isn't found.

module.exports = { root: './src/html' }

Note that nunjucks only resolves files in the specified/default template directories, and dies with a misleading error about the file not existing if an attempt is made to access a template outside these directories. This applies to nested template dependencies, but also to top-level entry files i.e. this won't work:

module.exports = {
    root: './src/html',
}
$ parcel ./index.html.njk
# error: ./index.html.njk: template not found: ./index.html.njk

The solution is to add the parent directories of entry files that are nunjucks templates to the list of template directories, e.g.:

module.exports = {
    root: ['./src/html', '.'],
}
$ parcel ./index.html.njk
# OK

DEVELOPMENT

NPM Scripts

The following NPM scripts are available:

  • build - compile the code and save it to the dist directory
  • build:doc - generate the README's TOC (table of contents)
  • clean - remove the dist directory and other build artifacts
  • rebuild - clean the build artifacts and recompile the code
  • test - clean and rebuild and run the test suite
  • test:run - run the test suite

COMPATIBILITY

SEE ALSO

  • nunjucks - a Jinja2-inspired templating engine with support for template inheritance
  • posthtml-extend - a PostHTML plugin which supports Jade-like template inheritance
  • posthtml-include - a PostHTML plugin which supports HTML transclusion

VERSION

2.2.2

AUTHORS

COPYRIGHT AND LICENSE

Copyright © 2017-2020 by Matthew McCune.

This is free software; you can redistribute it and/or modify it under the terms of the MIT license.

parcel-plugin-nunjucks's People

Contributors

chocolateboy avatar dependabot[bot] avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

parcel-plugin-nunjucks's Issues

Content inside raw/verbatim block is still processed by PostHTML

Hi,

I noticed HTML content between raw blocks are still processed by PostHTML. So this :

{% raw %}
<img src="{{ data.image }}" >
{% endraw %}

will trigger a build error {{ data.image }}: ENOENT: no such file or directory

I don't know if this issue is out of scope (as writing an html string directly inside Nunjucks tags would work), do you consider this expected behavior ?

Thank you

Nunjucks configuration file is Ignored

Hi!

First of all thank you for the configuration support! Now I fell like I can use in production because there's no limitations.

Unfortunately, I did set that nunjucks configuration file (nunjucks.config.js) in the root of my project and I tried to add some global variable just to test that new feature. But it seems to ignore that configuration file and nothing happens. The global variable is empty and template does not display the value... I don't have a clue why is not loading those configurations.

nunjucks.config.js
`const nunjucks = require('nunjucks')
const env = nunjucks.configure('./src')

module.exports = {
env,
data :{ name: 'It is working!' }
}
`

layout.njk
...
<title>Boilerplate - Light | {{name}}</title>

Name is empty

Load pages from sub directories

Is there a way to have pages in sub folders? Right now they only work if all the sites pages are in the root. Not sure if I am missing something with the config?

Templates in parent directories can't be referenced

parcel-plugin-nunjucks1.0.0
parcel1.9.7, 1.10.0-beta.1
nodev10.11.0
OS Linux (Arch)

(This is mentioned in #4 (and #7), but is broken out here as improving the documentation is a separate issue.)

Affected directives:

Currently the base template directory is set to the directory of each template asset e.g. if the template is located at src/html/screens/page-1.html.njk, the base template directory for the nunjucks environment associated with that file is src/html/screens. nunjucks doesn't allow templates to be loaded "outside the box" of the template directory, for security reasons, so referencing a template in a parent directory (e.g. ../macros/util.html.njk) ends up failing silently, by default (with or without Parcel) e.g.:

src/html/screens/page-1.html.njk

{% import "../macros/util.html.njk" as util %}

<h1>Welcome to Page 1!</h1>

test-default.js

const nunjucks = require('nunjucks')
const Path     = require('path')

const templatePath = Path.resolve('./src/html/screens/page-1.html.njk')
const templateDir = Path.dirname(templatePath)
const env = nunjucks.configure(templateDir)

try {
    const result = env.render(templatePath)
    console.log('result:', result)
} catch (err) {
    console.error('error:', err)
}

Output

result: null

Adding error reporting doesn't help as nunjucks doesn't flag the violation where it occurs, which leads to a cryptic error downstream complaining that a file that exists is not found:

test-error.js

const nunjucks = require('nunjucks')
const Path     = require('path')

const templatePath = Path.resolve('./src/html/screens/page-1.html.njk')
const templateDir = Path.dirname(templatePath)
const env = nunjucks.configure(templateDir)

function report (err, result) {
    if (err) {
        console.error('error:', err)
    } else {
        console.log('result:', result)
    }
}

try {
    env.render(templatePath, report)
} catch (err) {
    report(err)
}

Output

error: Template render error: (src/html/screens/page-1.html.njk)
Error: template not found: src/html/macros/util.html.njk

npm version is not up to date with latest merge

This means all changes introduced here are unavailable by using npm install parcel-plugin-nunjucks, including dependency management. Installing from the github using npm install devmattrick/parcel-plugin-nunjucks solves this.

Using Nunjucks inheritance

Is there any way I can get Nunjucks inheritance (extends) to work?

It looks like the plugin uses Nunjucks renderString to parse the template (and not the FileSystemLoader).

If it's not possible, is there an alternative way to achieve having 'master' templates such as the example below?

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <meta http-equiv="x-ua-compatible" content="ie=edge">
        {% block header %}{% endblock %} 
    </head>
    <body>
        {% block content %}{% endblock %} 
    </body>
</html>

Trigger live reload when a template is updated

My project uses template inheritance and a lot of included sub templates to manage the markup, with an entry point file (index.njk) that looks like this:

{% extends './templates/partials/_wrapper.njk' %}

{% block content %}

  {% include './templates/masthead.njk' %}

  {% include './templates/news.njk' %}

  {% include './templates/intro.njk' %}

  [...]

{% endblock %}

All of this structure works fine, except my live Parcel development server only refreshes the markup when index.njk is updated, not any of the templates it imports.

Is there any way to get Parcel to recognise when a sub template has been updated and refresh the markup?

Template errors are silently swallowed

parcel-plugin-nunjucks1.0.0
parcel1.9.7
nodev10.9.0
OS Linux (Arch)

Many types of error inside templates are not reported. This is due to a bug in nunjucks which throws errors asynchronously (and thus invisibly) if render or renderString are called synchronously.

$ cat example.njk
{% include "no-such-file.html" %}

<h1>Example</h1>
$ parcel build example.njk
# no error

$ cat dist/example.html
null

Feature: generate multiple outputs from one template file

In my case, I want to generate multiple outputs from one template file by specifying different nunjucks configurations. Each configuration file represents the same content but in different languages. Is it possible to achieve with the current v1.1.0 or not?

Support other types than HTML

(Moved from #2 as that's a separate issue.)

The plugin currently delegates to HTMLAsset in all cases, which means it only works with HTML templates, but there are plenty of other uses for nunjucks templating e.g. documentation (plain text, Markdown), code-generation (JavaScript) etc.

Assuming Parcel provides a way to map an extension (e.g. .json) back to its asset handler (e.g. JSONAsset), an option to support dual extensions would solve this nicely e.g.:

  • .html.njk -> NunjucksAsset -> HTMLAsset
  • .json.njk -> NunjucksAsset -> JSONAsset

etc.

No recompilation on change

Hi,
I expect issues with this package.
When a file was modified, absolutely nothing happend;

Current behaviour
I edit a .njk file -> I refresh the browser -> I see that the edition isn't propagated

Expected behaviour
I edit a .njk file -> I refresh the browser -> I see, like for .html file, the updated file

Note that options: { noCache: true } or restarting parcel does not even works to update output.
I need to force the update by remove .cache and dist folder.

Do I have miss to do anythings ?

Thanks

Build Nunjucks AST instead of passing to HTMLAsset

The current functionality is to simple compile the Nunjucks template and then pass it to the HTMLAsset where it is turned into an AST using JSDOM. It may be beneficial performance-wise to use Nunjucks to generate an AST and resolve dependencies from there.

Ideally, the Nunjucks compiler should be used so there are no compatibility issues.

Can't get the plugin to work

Upon installing the plugin, creating a nunjucks.config.js and executing parcel src/html/index.njk, Parcel can not resolve the entry:

Cannot resolve entry "/Users/myuser/myfolder/Parcel-playground/src/html/index.njk" from "/Users/myuser/myfolder/Parcel-playground/src/html"

Is there something I'm missing?

Referencing an HTML file in an anchor will break the compilation

Suppose that I have two files: 1.njk and 2.njk. The content of 2.njk does not matter, and let 1.njk contain an anchor to it.

<a href="2.html">...</a>

This will fail to resolve with the following error:

...: 🚨  /.../1.njk: ENOENT: no such file or directory, open '/.../2.html'

That's because that 2.html is compiled from 2.njk in fact. However, I cannot simply name them with the html extension, since they need to be explicitly in njk extension for compilation. A workaround is to point the anchor to 2.njk, but I think it is weird for an HTML to link to a template.

Parcel v2 support

Question

Parcel v2 is still in alpha, but looks very promising. I suppose this plugin will currently not work with v2 as they changed the overall architecture quite a bit.

Is there any chance there will be a v2-compatible version anytime soon?

We are relying on nunjucks templates for our app and would love to take Parcel 2 for a spin... 😇

Btw, thanks for putting this plugin together! It's often the small puzzle pieces like this plugin that don’t get the recognition they deserve, but can make all the difference.

Add support for other extensions

As a standard, Nunjucks has adopted .njk as an extension, however there are some people who may be using other extensions such as .nunjucks or even .html. I'm not exactly sure how to handle this sort of issue.-

Styles are included only in single page while extending template

Environment

https://github.com/uNmAnNeR/flashrepair-fe/blob/master/package.json

  • Node.js version: v12.8.0
  • OS: Win 10 x64

Describe the bug

here is my project starter
styles is included in js, and js is included in layout.
There are 2 pages extend layout. Javascript is appeared on both, but style included only on one of pages.

Expected behavior

Style should be included in every page which extends layout.

To reproduce

https://github.com/uNmAnNeR/flashrepair-fe/

npm start
check styling

Is there a way to set data dynamically ?

Hi,

Thanks for the nice plugin. I was wondering if there was a way to inject dynamic data to the template? Right now having to use a predefined config file make it really difficult (unless I'm missing something).

.nunjucksrc

{
    root: ".",
    data: { foo : "bar"}
} 

What if I want to inject a foo2 prop inside a specific template ? This is working :

index.html.njk

...
{% set foo2 = 'bar2' %}
{{ foo2 }} 

but this is not :
index.html.njk

...
{% set foo2 = 'bar2' %}
<script src="./script.js.njk" ></script>

script.js.njk
{{ foo2 }} // Output nothing

The only solution I am considering right now is to fs.writeFile the .nunjucksrc, is there better to do ?

Thank you !

Documentation or some kind of examples

Hi,

First of all thanks for your contribution, but, since Parceljs is a new thing, the most of the people doesn't know it very well.

It would be pretty nice to have some kind of example of how to use it... I just installed and it doesn't work as I expected, it just not compile nunjucks templates at all. I believe that's something I'm doing wrong, but it's impossible to know if there's no documentation at all.

syncPromise is not working

Environment

  • parcel-plugin-nunjucks version: v2.1.1
  • Parcel version: v1.12.4
  • nunjucks version: v3.2.0
  • Node.js version: v12.12.0
  • OS: macOS (Mojave 10.14.6)

Describe the bug

Parcel starts ⠋ Building... and wait forever. After research i found that syncPromise(asset.getConfig(...CONFIG_FILE)) || {} in node_modules/parcel-plugin-nunjucks/dist/NunjucksAsset.js is never ends.

As i see this behaviour already described in parcel-bundler/parcel#3566

Expected behavior

Parcel build the project.

To reproduce

  1. Use NodeJS 12.12.0 and minimal Parcel project from README.md
  2. Add parcel-plugin-nunjucks to package.json file
  3. Execute npx parcel build and wait forever...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.