Basically, a three-liner:
const templateText = await Deno.readTextFile(Deno.args[0]);
const render = new Function("return `" + templateText + "`").bind(templateParams);
console.log(render());
It uses interpolated JavaScript template strings (aka template literals) to process a generic text template file. For example:
# example of a YAML template
request:
ip: ${ this.dateTime.client_ip }
ip_time_zone: ${ this.dateTime.abbreviation }
server_utc_time: ${ this.dateTime.utc_datetime }
local_time: ${ new Date() }
Here, this
refers to the templateParams
object we passed from the above Deno script. This text file is in fact just a multi-line template strings, with all the corresponding syntax rules you'd follow inside a JavaScript "backtick" string. Hey, it's even possible to use await
inside `${...}`
:)
What is this useful for?
I believe it can be useful for build automation, including certain CI/CD-related tasks.
Deno itself is a very self-cointained JavaScript/TypeScript runtime engine. It comes as a single executable file which can be used without any external dependencies. Yet it offers an extensive built-in API to deal with files, networking etc.
More so, any specific Deno version can be easily installed into a local folder without admin rights. E.g., to install Deno v1.10.3 on Windows with PowerShell:
# install Deno v1.10.3 into ./bin
$env:DENO_INSTALL = "$pwd"
$v="1.10.3"
iwr https://deno.land/x/install/install.ps1 -useb | iex
Personally, I've never been comfortably fluent with Bash, PowerShell etc., so I find Deno very handy for quick, shell-like scripting with JavaScript. With Deno, I can quickly run a one-liner like this:
$ deno eval -p "await fetch('https://example.com').then(r => r.text()).then(t => t.match('example'))"
Of course, Deno is much more capable than that, but that's outside the scope of this article.
An example of templating
This example is a bit contrived, but it illustrates the purpose. Here we make a simple fetch
request to https://worldtimeapi.org/api/ip and save the results, using the above YAML template:
// deno run --allow-read --allow-net nascentTextGen.js sample.yaml.template
const templateParams = {
dateTime: await fetch("https://worldtimeapi.org/api/ip").then(r => r.json()),
args: Deno.args
};
const templateText = await Deno.readTextFile(Deno.args[0]);
const render = new Function("return `" + templateText + "`").bind(templateParams);
console.log(render());
Output:
# example of a YAML template
request:
ip: a.b.c.d
ip_time_zone: AEST
server_utc_time: 2021-06-04T01:32:56.595373+00:00
local_time: Fri Jun 04 2021 11:32:55 GMT+1000 (Australian Eastern Standard Time)
Code
Clone or fork this simpe demo project. Then:
- to install Deno (PowerShell):
pwsh -f _installDeno.ps1
- to run the sample:
pwsh -f _demo.ps1
Some more advanced general-purpose templating tools
This little project was inspired by a search for a JavaScript-based general-purpose text templating tool.
Of course, this approach may only be useful for simple, "logic-less" templates. If you need branching and looping constructs like if
, for
, while
or function
, there are a lot more powerful and actively maintained alternatives out there:
- Nunjucks: https://github.com/mozilla/nunjucks (there's even a VSCode extension for Nunjucks)
- Mustache: https://github.com/janl/mustache.js
- EJS: https://github.com/mde/ejs
- T4 (C#/.NET): https://github.com/mono/t4
- and more...
Top comments (3)
This will not work on Deno deploy btw
That makes sense for security reasons, but it works locally or inside a docker container.
It indeed does, I do however like the idea a lot, and wish it was possible in Deploy (for other reasons than running untrusted code)