These days, the most prevalent pattern for web development is to have one or more APIs and a Single Page Application (SPA) that coordinates calling these APIs and representing their output as HTML in a dynamic, client-side web application.
Especially with dedicated development frameworks and specialised build toolchains, this new approach is a great way to get to a result quickly and efficiently.
However, there is still a case to be made for server side rendered HTML. Indeed, newer frameworks like Vue and React offer a hybrid approach that lets you serve up parts of your HTML as interpreted on the server and made dynamic by rehydrating it on the client.
That's not what this article is about.
This article will demonstrate how to drag a somewhat old-school templating technology into a modern hosting stack: We're going to use Cloudflare's Workers to serve up Handlebars templates.
To do this we will take the following steps:
handlebars related dependencies to the Wrangler project;package.json; andDue to the set of technologies Cloudflare uses to make Workers possible, core Node modules are not available, including fs. Unfortunately, the full Handlebars engine uses it to load files from disk, disqualifying it from being used.
The runtime-only version of Handlebars on the other hand is smaller and does not rely on these Node packages.
The only prerequisite of using the Handlebars runtime-only version is that all templates must be precompiled. Our project needs to be extended with a Custom Build step in the wrangler.toml file.
Another constraint is that require-ing other files is not allowed without enabling the NodeJS compatibility layer, which will reduce performance of your Cloudflare Worker significantly.
For bonus points, we have also extended the registerHelper functionality of Handlebars to support asynchronous operations so that we can perform more complicated operations if we so desire.
The rest of these instructions assume the following:
views folder in the root of your projectpages and partials.assets folder in the root of your projectAdd the following dependencies to your package.json:
"handlebars": "^4.7.7",
"hbs-async-render": "^1.0.1"
And add this to your devDependencies section:
"hbs-import-transpile": "^1.0.4"
The handlebars module provides the Handlebars runtime-only environment. The hbs-async-render module allows us to register and succesfully evaluate Handlebars helpers that return Promises rather than content.
Lastly, we need the hbs-import-transpile for a compile-time file manipulation that will let us use the CommonJS output generated by the handlebars command line tool with import rather than require.
package.json scriptsWe are you going to add three new scripts to the package.json file.
The first calls the handlebars command-line tool. If you have not yet installed, please make sure you run the command below:
$ npm install -g handlebars
The second will take the output from the tool and transpile it for use as an import rather than require.
Lastly, we are adding another script target that can run these script in one go.
"handlebars": "npm run compilehbs && npm run transpilehbs && rm src/*-original.js",
"compilehbs": "handlebars -e hbs -f src/pages-original.js views/pages/ && handlebars -e hbs -p -f src/partials-original.js views/partials/",
"transpilehbs": "hbs-import-transpile src/pages-original.js > assets/pages.js && hbs-import-transpile src/partials-original.js > assets/partials.js"
The rm command in the handlebars target cleans up the output from compilehbs.
Updating wrangler.toml to run Custom Build step
Add the following to your wrangler.toml file to enable a custom build step that invokes the handlebars target from the package.json.
[build]
command="npm run handlebars"
watch_dir="views/"
Any time a file in the views/ folder is touched, your Worker will recompile the handlebars templates, the rest of the codebase, and deploy it to your function in the cloud.
Now that we have configured out Cloudflare Workers project to precompile Handlebars templates, let's try creating some code with it.
You can find the Github Repository here: