Port a URL shortener web App from Deno Deploy to Cloudflare

· Cotton's blog


Recently I made a URL shortener web App jsr:@indirect/short that is using JSR only (i.e. npm free) and could be setup on the Deno Delpoy Playground with just a one-liner:

1export { default } from 'jsr:@indirect/short@1'

or in command-line:

1deno serve -N --unstable-kv jsr:@indirect/short@1

I wondered how much effort it would take to make it deployable to Cloudflare Workers as well. Since used Hono as an underlay, which is platform-agnostic to begin with, this should be pretty easy to do, with only a few

Caveats #

WebAssembly #

The hashing function used here is FNV-1a from jsr:@std/crypto built by its WASM code. Unfortunately, it's not supported out of the box by Cloudflare Workers:

Cloudflare Workers deals with wasm differently than other runtimes. Specifically, you can't initialise an instance from a string like above, it has to be a separate modules that's imported.1

To work around this, replacing it internally with the pure JS version from npm @sindresorhus/fnv1a instead.

KV Bindings #

Unlike the Deno KV, which could be freely accessed via a global reference, the Cloudflare KV bindings have to be acquired from the routing context. The official solution from Hono is to use the built-in context storage middleware, which uses AsyncLocalStorage underneath enabled via nodejs_als:

1# wrangler.toml
2
3compatibility_flags = [ "nodejs_als" ]

Using .jsx / .tsx from JSR #

The support for .jsx / .tsx on JSR is half-baked at the moment2. Therefore, using it on a platform other than Deno Deploy requires additional manual tweak, mainly to adjust the import path that remains after JSR installation:

1# wrangler.toml
2
3[build]
4command = "node build.mjs"
 1// build.mjs
 2
 3import * as esbuild from 'esbuild';
 4
 5import { esbuild_plugin } from '@indirect/short/hotfix';
 6
 7await esbuild.build({
 8    entryPoints: [ 'main.js' ],
 9    bundle: true,
10    format: 'esm',
11    platform: 'node',
12    target: [ 'node20', 'es2022' ],
13    plugins: [ esbuild_plugin ],
14    outfile: 'bin.js',
15});

Putting all of the above together, I've created a template repo for easy setup. Feel free to give it a try.

Compare #

Deno Deploy

In retrospect, it has been such a smooth experience to take TypeScript, JSR, and Deno Deploy as a complete package deal. However, over the years, the Deno Deploy platform has always felt like a show house, by and large.

Deno KV was announced in May 2023, with an open beta in September. To this day (Dec 2024), it is still behind the switch of --unstable-kv.

The deploy feedback issue repo has barely received any attention. To me, it's unclear where Deno Deploy as a platform is headed.

Cloudflare

They have a wide product lineup to experiment with, and it can take you quite far even with the free-tier offering.

I wish it could expand better support for JSR, reduce the friction to allow dev focus more on writing code instead of manually wiring things up, i.e. the one-liner deploy through playground for import npm: or jsr: prefix without touching package.json and .npmrc at all.

It's funny that I started this project by selecting Hono (being acquired by Cloudflare) for use on Deno Deploy, with a few tweaks to deploy it back onto Cloudflare, which completing the circle.

BYOC (Bring Your Own Cloud) #

That's it: a dedicated URL shortener web App, with no tracking, privacy concerns, or risk of rug pulls. You manage your own data, usage, and deployment.

With only one-liner…ish.