Fork me on GitHub
#shadow-cljs
<
2022-09-14
>
Ferdinand Beyer13:09:33

Has anyone successfully built a VS-Code Web Extension with shadow-cljs? I need to target the browser, but cannot use any kind of library loading, and need to export functions to the exports symbol. It seems that when using the :export metadata on a function shadow emits a goog.exportSymbol call, but this one is not picked up by VS-Code. I think it "exports" to goog.global, which is this || self, but not exports. I can set the JavaScript properties to js/exports manually and it seems to work, but this seems like a hack?

thheller13:09:37

@fb do you have a link to some docs? does it support ESM?

Ferdinand Beyer13:09:24

I think it does not. I tried using the :esm target but this threw errors that export was not defined https://code.visualstudio.com/api/extension-guides/web-extensions

thheller13:09:06

js/exports is a hack and should not be done

thheller13:09:01

hmm yeah seems like ESM is not supported

thheller13:09:11

so you can use the :node-library target

thheller13:09:22

but watch/compile likely won't work (they assume a node env) and only release might

Ferdinand Beyer13:09:05

Similarly, I need to keep using require for "vscode", but not for others. I am using this in my build config:

:js-options {:js-provider :shadow
                :keep-native-requires true
                :keep-as-require #{"vscode"}}
This seems to work; however, for some reason my compile output now also wants to require("path") which does not exist, when I (:require ["vscode-languageclient/browser" :as browser]). The browser lib is specifically for this purpose and should not use "path"...

Ferdinand Beyer13:09:38

I tried :node-library but get errors about global being undefined. I figured this is just for node, not for browsers

pez15:09:36

Interesting. We're using :node-library in both Calva and Joyride. Maybe that closes the door for enabling them for the Web version of VS Code...

Ferdinand Beyer15:09:38

Probably. Meanwhile I am following Thomas' hints and build :npm-modules and process them with webpack. I hope I never have to step through the resulting JavaScript by hand 😄

pez16:09:20

We're also using Webpack. Very happy there are these tools like shadow and webpack and such!

Ferdinand Beyer16:09:10

But they make me dizzy 🙂

Ferdinand Beyer16:09:40

ClojureScript, Closure Compiler, Shadow, Webpack -> Who is contributing what? 😄

pez17:09:15

Throw Tailwind CSS into the mix, with it's PostCSS pipeline, while at it. 😃

thheller13:09:26

correct, it assumes node

thheller13:09:04

your best bet is probably using :target :npm-module and using their webpack example config

thheller13:09:22

REPL and hot-reload probably won't work though

Ferdinand Beyer13:09:27

Yeah, I figured that much, as I need "all in one JS file"

Ferdinand Beyer14:09:50

Trying this path... I now get "`process` is not defined", and indeed the beginning of cljs_env.js reads:

var $CLJS = {};
var CLJS_GLOBAL = process.browser ? (typeof(window) != 'undefined' ? window : self) : global;
Looks like this, too, is targeting node?

Ferdinand Beyer15:09:47

Oh, nevermind, I think I am entering the dark realms of polyfills 😕

thheller16:09:04

not polyfills but yeah. the targets are all designed to make specific assumptions about their environment

thheller16:09:37

so your web extensions is just another very locked down target with very specific kind of expectations

thheller16:09:09

so this would be a custom :target that just emits exactly what the web extensions expects

thheller16:09:18

there just isn't one like that currently 😛

Ferdinand Beyer16:09:53

Maybe I can help one day, currently I am not too deep into the muddy waters of JavaScript builds 🙂 I said polyfills because I needed to configure webpack to provide polyfills for process (among others), and then it worked. Even though I am probably pulling in a process implementation just for the process.browser flag 😄

thheller16:09:06

yeah webpack v4 always provided this but v5 no longer does

thheller16:09:59

I should just get rid of it entirely but don't want to break stuff for people that may rely on it 😛

Ferdinand Beyer16:09:22

Get rid of what?

thheller16:09:19

the process.browser check

Ferdinand Beyer16:09:10

Ah, I was not even aware that this is yours 😄

thheller16:09:35

yeah :npm-module adds it so it works in node and the browser

Ferdinand Beyer16:09:36

Is there a way to do !process || process.browser?

thheller16:09:56

that would still make webpack v5 unhappy because process is undefined

Ferdinand Beyer16:09:10

typeof(process) === undefined?

thheller16:09:04

did you set :runtime :browser in the build config?

thheller16:09:10

that would also get rid of it 😉

thheller16:09:13

forgot to mention this

thheller16:09:34

although it might also not like the globalThis

thheller16:09:45

dunno enough about the web extension context runtime

Ferdinand Beyer16:09:57

In the end it will run in a browser

Ferdinand Beyer16:09:18

And for testing they have some kind of fake for that

Ferdinand Beyer16:09:39

Hm, does not seem to make a difference. But I also don't see the process.browser bit anymore in the output files. Will keep an eye on it

pez15:09:48

Maybe of particular interest to shadow-cljs users (at least the ones also using #calva). @danielamber2 and I have made a video about using Calva with shadow-cljs, where we also try to reveal some of the details and how things are composed to make it all work. Some of it applies generally to nREPL tooling, so CIDER (and other nREPL clients) users might also enjoy. I do hope I am not misinforming too much about things there, please let me know if you spot any such. https://www.youtube.com/watch?v=islMjv55cN8 I have also written an article about the same subject. https://blog.agical.se/en/posts/shadow-cljs-clojure-cljurescript-calva-nrepl-basics/ Pick whichever way you fancy. I think they go great together. 😃

👍 3