Im trying to build a cloudflare durable object worker with clojurescript. Im having a few problems with this because when building cloudflare workers with Durable objects you need to extend the DurableObject class. I've been able to work around that with the shadowcljs macro "defclass" but because the durableworker Class actually gets injected at run time, the clojurescript compilation fails like this.
[:api] Compiling ...
The required JS dependency "cloudflare:workers" is not available, it was required by "api/auth/durable_objects/user.cljs".
Dependency Trace:
api/core.cljs
api/auth/durable_objects/user.cljs
Searched for npm packages in:
/Users/mlakewood/projects/school-apps/node_modules
See:
My shadowcljs edn file is
{:nrepl {:port 8777}
:source-paths ["src" "test"]
:dependencies
[[reagent "1.1.1"]
[re-frame "1.4.2"]
[day8.re-frame/tracing "0.6.2"]
[metosin/reitit "0.7.0"]
[metosin/malli "0.16.3"]
[clj-commons/pushy "0.3.10"]
[garden "1.3.10"]
[net.dhleong/spade "1.1.0"]
[re-pressed "0.3.2"]
[binaryage/devtools "1.0.6"]
[day8.re-frame/re-frame-10x "1.9.3"]
;; API client dependencies
[cljs-http "0.1.46"]
[day8.re-frame/http-fx "0.2.4"]]
:dev-http
{8280 "resources/public"
8290 "target/browser-test"}
:builds
{:app
{:target :browser
:output-dir "resources/public/js/compiled"
:asset-path "/js/compiled"
:modules
{:app {:init-fn school-apps.core/init}}
:devtools
{:preloads [day8.re-frame-10x.preload]}
:dev
{:compiler-options
{:closure-defines
{ re-frame.trace.trace-enabled? true
day8.re-frame.tracing.trace-enabled? true}}}
:release
{:build-options
{:ns-aliases
{day8.re-frame.tracing day8.re-frame.tracing-stubs}}}}
:browser-test
{:target :browser-test
:ns-regexp "-test$"
:runner-ns shadow.test.browser
:test-dir "target/browser-test"}
;; NEW: API backend build for Cloudflare Workers
:api
{:target :esm
:runtime :node
:output-dir "dist/api"
:modules {:main {:exports {default api.core/main-handler
UserStore api.auth.durable-objects.user/UserStore
SessionStore api.auth.durable-objects.session/SessionStore}}}
:compiler-options
{:optimizations :simple
:target :es2020
:closure-defines {goog.DEBUG false
goog.ENABLE_DEBUG_LOADER false}}}}
:karma-test
{:target :karma
:ns-regexp "-test$"
:output-to "target/karma-test.js"}}}I was able to get it to compile by adding this to the :api target
:js-options
{:resolve {"cloudflare:workers" {:target :global
:global "globalThis"}}}
But predictably when it actually runs it fails because the compiled file is pointing at "globalThis" and the cloudflare worker barfs.I think you also need :js-options {:js-provider :import} setting
at least this setup worked for me before https://github.com/roman01la/uix-cloudflare-template/blob/master/shadow-cljs.edn
as a side note, durable objects are quite a pita to use in cljs, they can't implement protocols other than default Object protocol, since implementation of protocols in cljs breaks DO's runtime requirements (transparent de/serialization of data coming in and out of DOs)
Hmm interesting. I think there is a lot to unpack there. Is it connected with the way you have to extend the DurableObject class? So essentially use their interface? Or does it run deeper that than. BTW that worked! Thanks!
by default :target :esm will try to bundle all its dependencies. so it tries to find cloudflare:workers in node_modules, which doesn't exist and thus fails. :js-provider :import tells it to not bundle anything and just try to import it at runtime instead. an alternative is have shadow-cljs bundle everything except a few packages via :js-options {:keep-as-import #{"cloudflare:workers"}}
as for classes that need to extend something, you can use the defclass macro https://clojureverse.org/t/modern-js-with-cljs-class-and-template-literals/7450