DEV Community

Muhammad Ridho
Muhammad Ridho

Posted on • Edited on

Deploy your ClojureScript App to Cloudflare Workers

Updated: 19-Jul-2023

Its now easy to deploy ClojureScript compiled output to Cloudflare workers.

Since the recent update with regards to node.js compatibility, no need for clever tricks anymore.

Here is step by step poc:

$ cd /tmp
$ pnpm create cloudflare@latest

In which directory do you want to create your application?
dir ./hello2

What type of application do you want to create?
type "Hello World" Worker

Do you want to use TypeScript?
no

Retrieving current workerd compatibility date
compatibility date 2023-07-17

Do you want to use git for version control?
no

Do you want to deploy your application?
no

$ cd hello2
Enter fullscreen mode Exit fullscreen mode

At this point, check if we're ready to continue.

$ pnpm exec wrangler --version
 โ›…๏ธ wrangler 3.0.0 (update available 3.3.0)
Enter fullscreen mode Exit fullscreen mode

Now add shadow-cljs.

$ pnpm install --save-dev shadow-cljs@latest
Enter fullscreen mode Exit fullscreen mode

Shadow-cljs just need simple configuration, we can generate default config with pnpm exec shadow-cljs init or just create one by ourself.

$ cat <<EOF > shadow-cljs.edn
{:source-paths ["cljs/main"]
 :dependencies []
 :builds {:cf {:target :npm-module
               :output-dir "out"
               :entries [hello]}}}
EOF
Enter fullscreen mode Exit fullscreen mode

Then modify its content to be like below, the important part is that we set :target to :node-module.

Next, verify if shadow-cljs is ready. This will download required clojure/java/maven dependencies if necessary.

$ pnpm exec shadow-cljs info
Enter fullscreen mode Exit fullscreen mode

One more step in cljs part is create our sample source file:

$ mkdir -p cljs/main
$ cat <<EOF > cljs/main/hello.cljs
(ns hello)

(defn ^:export message []
  "Hello from Clojurescript")
EOF
Enter fullscreen mode Exit fullscreen mode

Partly done, take a breath first.


Now, for this demo, we compile the cljs source like so:

$ pnpm exec shadow-cljs release :cf
Enter fullscreen mode Exit fullscreen mode

It will put the compiled output to ./out/ directory. Now lets modify workers entry file in src/worker.js, for this demo, we import the compiled cljs output and use it there somehow, like shown below:

import { message } from '../out/hello';

export default {
    async fetch(request, env, ctx) {
        return new Response(message());
    },
};
Enter fullscreen mode Exit fullscreen mode

Only final important step is to activate the node compatibility in wrangler.toml, set node_compat = true.

Our full wrangler.toml file now would look more or less like this:

name = "hello2"
main = "src/worker.js"
compatibility_date = "2023-07-17"
node_compat = true
Enter fullscreen mode Exit fullscreen mode

Ok, its done now.


We could test it first locally:

$ pnpm exec wrangler dev
Enter fullscreen mode Exit fullscreen mode

On separate terminal, test if dev server ok:

$ curl -v http://127.0.0.1:8787/
Enter fullscreen mode Exit fullscreen mode

No error, right. Okay, so lets ship it.

$ pnpm exec wrangler deploy
Enter fullscreen mode Exit fullscreen mode

It will authorize with your cloudflare account first before deploying, if every thing is ok, you would see message more or less like below:

...
Total Upload: 56.67 KiB / gzip: 11.25 KiB
Uploaded hello2 (4.46 sec)
Published hello2 (8.61 sec)
  https://hello2.datafy.workers.dev
Current Deployment ID: eae28984-581c-4ef2-b821-0932efac5003
Enter fullscreen mode Exit fullscreen mode

Thank you for reading.


Update

As of today, compile cljs to :esm is also works. Below are relevant changes:

shadow-cljs.edn

{:source-paths ["cljs/main"],
 :dependencies [],
 :builds {:cf {:target :node-module,
               :output-dir "out",
               :entries [hello]},
          :cf2 {:target :esm,
                :output-dir "out2",
                :modules {:hello {:exports {message hello/message}}}}}}
Enter fullscreen mode Exit fullscreen mode

src/worker.js

import { message } from '../out2/hello';

export default {
    async fetch(request, env, ctx) {
        return new Response(message());
    },
};
Enter fullscreen mode Exit fullscreen mode

wrangler.toml

name = "hello2"
main = "src/worker.js"
compatibility_date = "2023-07-17"
Enter fullscreen mode Exit fullscreen mode

Top comments (0)