Javascript lends itself really well to writing asynchronous code, but when you open up the JavaScript console in a web browser or the command-line interpreter in Node, it becomes annoying really fast to test out an asynchronous method and see what it returns.

The async/await pattern lends itself really well to writing code in a repl, and while you cannot use await in top-level JavaScript code, you can in the repl!

In the Chrome JavaScript console, you can just use await:

> await fetch('')
    .then(r => r.json())

{id: 4, type: "general", setup: "What do you call a belt made out of watches?", punchline: "A waist of time."}

With Node 10+ you can do --experimental-repl-await (thanks vsemozhetbyt!):

$ node --experimental-repl-await
> await require('fs').promises.readFile('hi.txt', 'utf8')


You can also go ahead and set an alias for node to use this flag by default.


Recently while working with the Liquid templating language in a Jekyll project, I found that I wanted to inline JSON data on a page, so I could render it dynamically with JavaScript. The quickest—but fundamentally insecure—way to do this is by using the jsonify filter to add an object to the page and then access that object in your script (React, Vue, Angular, whatever):

  window._DATA = {{ | jsonify }}; // this introduces an XSS exploit

Unfortunately, the jsonify filter is not secure (currently using Jekyll 3.8.5). In the above example, if is: </script><script>alert('hi!')</script>, then you’ll quickly see that this snippet of text gets injected verbatim into your template and you will receive a friendly greeting alert when you load the page. This is a cross-site scripting exploit (XSS).

The secure way that jsonify should work (which I think is how the Shopify json filter works) is to convert < and > within any strings it encounters to their unicode escape sequence, e.g., < -> \u003C and > -> \u003E and & -> \u0026. For additional context, here’s someone looking to handle the same issue while using expressjs.

To get around this issue in Jekyll, you can add an additional escape step to convert the whole object into an escaped string, then decode and parse it afterward:

  window._DATA = JSON.parse(decodeURIComponent("{{ | jsonify | uri_escape  }}"));

Now you’re safely preventing JavaScript from sneaking out of your data into the page!

Inline JSON tag


JSON.parse(decodeURIComponent("{{ | jsonify | uri_escape  }}"))

So you can now do: {% include json.html data=foo %}

Inline JSON tag for subset of object


{% assign keys = include.keys | split:"," %}{ {% for k in keys %}{{ k | jsonify }}: JSON.parse(decodeURIComponent("{{[k] | jsonify | uri_escape  }}")){% unless forloop.last %}, {% endunless %}{% endfor %} }

So you can now select only specific keys within the object, as such:
{% include json_from_keys.html data=foo keys="name,body,tags" %}

Happy coding!

Edit: FWIW, I noticed regular variables in templates aren’t escaped by default either. For example in a snippet such as {% assign foo = "This & that > those" %}{{ foo }} the > and & do not get html-escaped. This seems really strange and backward to me—perhaps someone more familiar with Jekyll has an idea why it works this way? I could see someone arguing that the content is all pre-generatd so you don’t have to worry about random UGC sneaking in to create XSS attacks, but basic HTML-escaping of content still seems like an entry-level feature for any modern HTML templating language?

A very short example of how to pass a function into setState in React. read full post…
A convenience function for writing mixed color and/or font-style text using the HTML5 canvas, which is made possible by the ctx.measureText method. read full post…
A brief redux-like example of why I think it’s useful to use curly braces around the statements after case clauses inside JavaScript switch statements. read full post…

Peter Coles

Peter Coles

is a software engineer who lives in NYC, works at Ringly, and blogs here.
More about Peter »

github · soundcloud · @lethys · rss

It’s time to get big money out of politics. Join the kick-started campaign to put government back in the hands of the people. Pledge now