DEV Community

Cover image for How Eleventy can write non-string data in JavaScript with Nunjucks
Benjamin Rancourt
Benjamin Rancourt

Posted on • Originally published at benjaminrancourt.ca on

How Eleventy can write non-string data in JavaScript with Nunjucks

After I found how I could have valid JavaScript files with the front matter block, I rapidly come across a new challenge: how can I access non-string Eleventy data in JavaScript with Nunjucks? 🤔

It may seem easy at first, but the difficulty resides in that I still want to be able to lint my *.js.njk as JavaScript… Let me show you an example:

/*---
html: "Hello world!"
tags:
  - eleventy
  - javascript
  - html
--------*/
import { LitElement, html } from 'lit-element';

class Post extends LitElement {
  render() {
    // Nunjunks variables are valid JavaScript inside a string
    const body = `{{ post.html }}`;

    // But outside, it will produce an error:
    // "Uncaught SyntaxError: Unexpected token '{'"
    const tags = {{ post.tags }};

    return html`
      ${tags}
      ${body}
    `;
  }
}

window.customElements.define('br-post', Post);
Enter fullscreen mode Exit fullscreen mode
Code example of a non-existent file named br-post.js.njk

Oops, I needed to find a workaround to that problem or my quick prototype to test if I could join Eleventy and Web Components will appear to be unsustainable… 😱

Fortunately, you may think that if I am writing this post, there is a good chance that I found a solution. And you are right. 😄 How? By using another time JavaScript comments. Let me show you how I came to that conclusion:

// Not valid JavaScript code :(
const anArray = {{ post.tags }};
const anObject = {{ post.author }};

// could be converted into
const anArray = [ 
  // {{ post.tags }}
];
const anObject = { 
  // {{ post.author }}
};

// and it would be valid, but our data would be inside JavaScript comments...
// Maybe a shortcode will help us transform our code
const anArray = [ 
  // {{ toJavaScriptArray post.tags }}
];
const anObject = { 
  // {{ toJavaScriptObject post.author }}
};

// to the content of the array *on a subsequent line*
const anArray = [ 
  //
  "eleventy", "javascript", "html"
];
const anObject = { 
  //
  firstName: "Benjamin", lastName: "Rancourt"
};

// Oh oh, I think we may be into something! ;)
Enter fullscreen mode Exit fullscreen mode

This solution may insert some blank comments, but if you minify your files before shipping them to production, they surely should be removed. 🧙

The shortcodes needed to do that are, in their simple forms, easy to implement:

const stringify = (object) => JSON.stringify(object);
const slice = (string) => string.slice(1, string.length - 1);
const decommentObject = (object) => `
  ${slice(stringify(object)}
`;

eleventyConfig.addShortcode('toJavaScriptArray', decommentObject);
eleventyConfig.addShortcode('toJavaScriptObject', decommentObject);

Enter fullscreen mode Exit fullscreen mode
Simple code that resolve our problem

You could add and adapt these lines, but I recommend that you check on the @sherby/eleventy-plugin-javascript NPM package. I have included in it more robust functions to help you write JavaScript code with Eleventy. I also add some functionalities that I leave you to take a look. 😉

To use this plugin, you only need to install the dependency with npm

npm install @sherby/eleventy-plugin-javascript --save-dev
Enter fullscreen mode Exit fullscreen mode

and to add the plugin into your Eleventy config file (.eleventy.js)

const eleventyPluginJavascript = require("@sherby/eleventy-plugin-javascript");
module.exports = (eleventyConfig) => {
  eleventyConfig.addPlugin(eleventyPluginJavascript);
};

Enter fullscreen mode Exit fullscreen mode

Let me know if this plugin helps you! 🍬

Top comments (0)