shadow-cljs

andrea 2025-02-22T19:22:29.721069Z

I'm trying to use https://pglite.dev/docs/ from within a cljs app and get some compiler errors about dynamic imports

;  ["@electric-sql/pglite" :refer [PGLite]]
;    ))
; Closure compilation failed with 4 errors
; --- node_modules/@electric-sql/pglite/dist/index.cjs:4
; Dynamic import expressions cannot be transpiled.
; --- node_modules/@electric-sql/pglite/dist/index.cjs:13
; Dynamic import expressions cannot be transpiled.
; --- node_modules/@electric-sql/pglite/dist/index.cjs:13
; Dynamic import expressions cannot be transpiled.
; --- node_modules/@electric-sql/pglite/dist/index.cjs:13
; Dynamic import expressions cannot be transpiled.
; 
And this is even after using :compiler-options {:output-feature-set :es2020} as mentioned in the https://shadow-cljs.github.io/docs/UsersGuide.html#_output_language_options but it's not helping (and I imagine this is because it's not about imports after all).

andrea 2025-02-22T19:25:26.924389Z

I'll be trying to use js-provider-external as mentioned here, but if there's a simpler way I'll be glad to hear about it https://clojurians.slack.com/archives/C6N245JGG/p1705701245163689?thread_ts=1705696515.599419&cid=C6N245JGG

thheller 2025-02-22T19:34:03.577269Z

unfortunately you likely wont have much luck with :external. dynamic imports make the code async, which will cause issues.

thheller 2025-02-22T19:34:54.700759Z

best option is like to use the CDN variant, i.e. keeping the whole thing out of the build entirely

thheller 2025-02-22T19:36:25.498369Z

> Dynamic import expressions cannot be transpiled.

thheller 2025-02-22T19:36:33.818089Z

this is the least of your worries if the package is WASM related

andrea 2025-02-22T19:36:56.291449Z

I've managed to use WASM for via js interop, to be seen how far I get with this

thheller 2025-02-22T19:37:23.081159Z

you can use :target :esm and use (:require ["" :refer (PGlite)])

thheller 2025-02-22T19:37:52.193349Z

i.e. translating this import { PGlite } from ""; from the README

andrea 2025-02-22T19:39:43.660209Z

not sure what output to expect from that. Will their code be bundled with mine, or will my users still make requests to the CDN? I imagine the latter

thheller 2025-02-22T19:41:40.629849Z

yes, users will load the files from the CDN. things will not be bundled this way

thheller 2025-02-22T19:42:00.207479Z

you could just place the files on your HTTP server, if you don't want the CDN dependency

andrea 2025-02-22T19:42:08.732579Z

yea that's what I was planning to do

andrea 2025-02-22T19:43:06.952339Z

just changing :target :browser to :esm does more things I don't understand yet (will the output have a different name or do I need to load it differently?)

thheller 2025-02-22T19:43:08.150549Z

(:require ["esm:/npm/@electric-sql/pglite/dist/index.js" :refer (PGlite)]) if you put the file in the public/npm/@electric-sql/pglite/dist/index.js with public being your http root (just an example, paths are up to you)

thheller 2025-02-22T19:43:29.566009Z

yes you need to add type="module" to the script tag loading the JS

🙏 1
thheller 2025-02-22T19:43:43.437149Z

otherwise things should be ok

andrea 2025-02-22T20:04:10.129429Z

Ahah I think I unlocked the next part of the challenge, of course it's chunked. This will keep me busy for some more time, Thank you Thomas!

thheller 2025-02-22T20:05:17.739719Z

those files should all be in the npm package, you'll likely need the whole dist folder

💯 1
andrea 2025-02-23T17:41:11.568269Z

So I made some progress and can get the library to work but I'm still messing something up with the imports. I have this at some point:

(:require
   ["esm:/static/pglite/index.js" :refer (PGlite)]
   ["@electric-sql/pglite/live" :as live]
   ["@electric-sql/pglite-sync" :as pglite-sync]...
And as-is it doesn't work, failing at page load with Uncaught Module not provided: module$node_modules$$electric_sql$pglite$dist$live$index_cjs BUT it works if I load the page with this code:
(:require
   ["esm:/static/pglite/index.js" :refer (PGlite)]
  ;;  ["@electric-sql/pglite/live" :as live]
  ;;  ["@electric-sql/pglite-sync" :as pglite-sync]
It loads successfully. Then I can uncomment the two lines and re-run the ns definition with the 3 :require from the REPL and I have those two available from the correct urls [see pic] It's as-if at page load is trying to find the live before PGlite or some other ordering issue I'm yet to get to the bottom of

andrea 2025-02-23T17:42:32.251859Z

(even though live is under pglite I didn't find the correct incantation to load it via esm:/ - and even then I have to see how to do it for pglite-sync which I imagine depends on the rest but it's in a separate module)

thheller 2025-02-23T17:44:44.499199Z

well you can't bundle parts but not others

thheller 2025-02-23T17:44:49.589649Z

so its either all esm or nothing

thheller 2025-02-23T17:46:35.562459Z

you can use browser import maps to help this along

andrea 2025-02-23T17:47:25.885559Z

That makes sense, leaving still to figure out: 1. How do I :refer something nested? (that pglite/live) 2. How do I require that pglite-sync if that depends on pglite via npm, I imagine at some point just copying dist directories to my static path stops working

thheller 2025-02-23T17:47:31.494189Z

for :esm builds set :js-option {:keep-as-import #{"@electric-sql/pglite" "@electric-sql/pglite/live" ...}}, which will keep shadow from bundling them

thheller 2025-02-23T17:47:45.815849Z

so you basically add all the electric things

thheller 2025-02-23T17:48:04.892109Z

but use just a regular (:require ["@electric-sql/pglite" ...]) in your code

thheller 2025-02-23T17:48:35.079069Z

then setup a import map in your browser to tell the browser where to get the actual files

thheller 2025-02-23T17:50:22.374179Z

I don't know what you are doing exactly but loading a 10mb+ sql server into a browser seems like madness to me 😛

🤣 1
thheller 2025-02-23T17:50:28.231719Z

still curious if you can actually get it to work

andrea 2025-02-23T17:51:38.547319Z

it's to build an app that is supposed to work offline, and sync with a remote server/other devices when online

andrea 2025-02-23T17:53:17.296269Z

I have a smallish prototype that saves just to idb, but works offline via service workers so if this works it'll be Cool™ but it's far form working at the moment 🙂 10Mb is not a lot if it's loaded just once and then available offline, but probably still insane 😄

thheller 2025-02-23T17:54:30.764209Z

I mean the alternate route is going with this https://shadow-cljs.github.io/docs/UsersGuide.html#_third_party_tool_integration

thheller 2025-02-23T17:54:44.067779Z

and then running the output through webpack or so after shadow-cljs is done with it

thheller 2025-02-23T17:55:04.546849Z

basically that puts webpack in charge of the npm stuff and shadow just does the CLJS parts

thheller 2025-02-23T17:55:15.914719Z

https://shadow-cljs.github.io/docs/UsersGuide.html#target-npm-module also works in the same way, just not using ESM. which may make things easier or harder. depends on the constellation of npm packages really 😛

thheller 2025-02-23T17:55:59.430049Z

import maps should work too though

thheller 2025-02-23T17:56:15.084999Z

really all depends on the npm packages. I don't know how they are setup

andrea 2025-02-23T17:56:21.971089Z

I've only ended up here because of the dynamic import I guess, so not sure where those stand with this

andrea 2025-02-23T17:56:46.911989Z

there's also wasm component (that so far gave no issues)

thheller 2025-02-23T17:57:04.836469Z

yeah because you didn't get to that part yet 😉

andrea 2025-02-23T17:57:56.030199Z

I think I did manage to get pg run in wasm, because I got some writes replicated, but I might be fooling myself

thheller 2025-02-23T17:58:45.123409Z

well shadow doesn't support any WASM bundling whatsoever, so if you manually tweak things long enough it might work. but definitely not out of the box 😛

👍 1
andrea 2025-02-23T20:07:01.683669Z

import map started to work and unlock new problems one at the time. Now I'm trying to load some mjs file and get Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "application/octet-stream". Strict MIME type checking is enforced for module scripts per HTML spec. So I believe the :dev-http server is not using the right content type to serve this. I guess luckily there's a index.legacy-esm.js in that path and that allows progress, so will use that for the the time being, but otherwise I guess I can't set a middleware for :dev-http and the only solution would have been to use a reverse proxy

thheller 2025-02-23T20:11:03.793119Z

I fixed that 2 years ago? which shadow version are you on? 😛

andrea 2025-02-23T23:35:21.102839Z

=== shadow-cljs version (via clojure/deps.edn) shadow-cljs version: 2.25.4 guilty! 😄