Simulating Apache mod_include for Vercel

I run a static site, it’s built with Hugo and hosted on the edge with Vercel. Sometimes, I just want to include a small piece of server-side logic (Copyright notice anyone?) without having to spin up a complex node server or api endpoints. Sometimes I want to be able to drop a small piece of dynamic content in one single page on my static site.

That’s what I loved about Apache mod_include. mod_include let’s you drop a specially formatted HTML comment in to your HTML template and Apache server would then ‘include’ the output of the command in your outputted HTML. e.g,<!--#include file="test.txt" --> which will include the content of a file where the include is and  <!--#include virtual="/api/time.js" --> would call a function and return the output in place of the include.

But how do you get it working for sites hosted with Vercel?

I wrote a little function (demo - note you can see a file included and also a function call) that you can use to simulate mod_include.

Vercel has a request router that is configured to rewrite all requests for html pages so that they pass through the ssi.js function which in turn will parse the requested html file looking for the includes to replace.

The implementation of file command (demo) is relatively straight forward using simple fs functions to inject content into a page. The virtual command (demo) is more interesting because I didn’t want to spin up a vm in node to execute a function so instead the handler uses http-fetch to call the file in /api directory. /api/ is the new /cgi-bin/ - I’m certainly open to suggestions if vm is a better solution, because the node-fetch certainly adds some extra latency.

You will want to make sure caching is properly enabled because you really don’t want to have to execute functions for every single page-view, you still want to get your ‘static’ pages cached on the edge.

I’m unsure if you should use this in production, I would love Vercel to offer something similar to cloudflare’s workers and HTMLRewriter that allow you to manipulate static files (or function response) before it’s sent to the client.

Picture of me smiling.

Paul Kinlan

I lead the Chrome Developer Relations team at Google.

We want people to have the best experience possible on the web without having to install a native app or produce content in a walled garden.

Our team tries to make it easier for developers to build on the web by supporting every Chrome release, creating great content to support developers on web.dev, contributing to MDN, helping to improve browser compatibility, and some of the best developer tools like Lighthouse, Workbox, Squoosh to name just a few.

RSS Github Medium