This Article IsCreated at 2024-04-19Last Modified at 2024-04-19Referenced as ia.www.b49

Server-Side Rendering with uhtml and Deno

A few days, I discovered a simple web framework by WebReflection and made a website out of it. The web framework - uhtml - is very simple, simple enough to have made me want to find a simple JS engine to pair with it. I initially chose QuickJS, and… let’s just say its ES module API is not ready for public use yet.

I then turned to Deno, which I use to render this website, and it immediately worked!

Below is a simple example you can run with deno run saved-filename.js.

import initSsr from 'https://esm.sh/uhtml@4.5.2/ssr';

const { html, render } = initSsr()

const abc = [1,2,3]

console.log(html`hi, i can count to three! ${abc.map((x,i) => html`${x}${i==2?'!':','}`)}`.toDOM().toString())

Look at uhtml’s documentation for more advanced usage.

The version pinning (@4.5.2) is necessary because…

The Types, They Go In And Go Out And Go In And Then Go In In Pairs

Originally, uhtml had a types folder, but I think it’s broken.

The author and I fixed it.

Someone broke it again for Deno.

I don’t understand this anymore.

See the PR history for more details.


Well, it seems like every Javascript runtime has its own set of module resolution rules and a separate set of type-module resolution rules. This is extremely cursed.

The one who broke the types for Deno told me about JSR. I will publish my packages there if I will have any. As it turns out, JSR is tightly integrated with Github, which is not great.

I recommend using your own git repo and pnpm. e.g. pnpm add https://example.com/your-repo/here.git


This is the second day. The typescript battle has come to an end.

So what’s the lesson here? Use JSDoc or TS. Ignore Node.js’ weird module resolution rules and use ESM with relative paths. If you have to support Node.js, use a bundler.

The snippet, upgraded but yet not upgraded

If anything goes right, the following code should work in Deno too with no change to functionality.

import initSsr from 'https://esm.sh/uhtml@4.5.8/ssr';

const { html, render } = initSsr()

const abc = [1,2,3]

console.log(html`hi, i can count to three! ${abc.map((x,i) => html`${x}${i==2?'!':','}`)}`.toDOM().toString())

Now I can sleep.