Hello. I've been trying to get the same code-base working with both NBB and Shadow-cljs, but this seems impossible (I expect I've done something stupid 😅). Shadow is configured as :target :esm. This is the same use case as referred to some time earlier in chat, but I've written it up here: https://github.com/dmg46664/problems/tree/main/03_nbb_and_shadow_import
You should probably write `
js/WebSocketServer
since it's a global
or not? is it coming from the ws package? I thought it was maybe some webstandard
anyway, according to that package on npm you should import it like this:
import WebSocket, { WebSocketServer } from 'ws';Thanks for the quick response. Yes, the server class is from ws as you've concluded. Assuming your last response means I should :require ["ws" :as WebSocket :refer [WebSocketServer]] then this works in Shadow but not in NBB.
damn.
well, not exactly
import Foo from 'ws' is (:require ["ws$default" :as Foo]) in CLJS, since Foo is the default export
Try this:
$ node --experimental-top-level-awaitx = await(import('ws'))> x.WebSocket
> x.WebSocketServer
[class WebSocketServer extends EventEmitter]hmm, both seem to work and this is normally what happens in nbb as well
I thought there needs to be an module.exports = { default: ... in order for there to be a default export?
no, module.exports isn't ES6
ES6:
export default ...Same for export default ... in ES6
yeah... but I don't see a default export in the ws code.... ?
To me it's weird that x = await(import('ws')) isn't the same as (:require ["ws" :as x]) in nbb, so this is something that needs to be investigated
it is the mixture of CJS and ES6 which complicates this a lot. if ws was exposed as an ES6 module, it would be the same I think
I swear this JS module stuff has done my head in 😅
So if I read your comments above correctly, I either need to do x = await(import('ws')) or node --experimental-top-level-await ? Much obliged!
I'm also glad that I'm not completely crazy!
what I meant to say was: you can check how modules are imported by doing that manually
but it's not exactly the same in nbb as when I'm doing that, which is what I would expect... it's complicated
this needs some debugging
Coolio, thanks for confirming. Yes I was reading your JS as assumed clojure, hehe. Should I leave this with you? Do you need anything else from me?
Or are you asking me to debug it?
if nbb behaves differently than shadow-cljs + target esm then I think it could be a bug in nbb: issue welcome
no problemo, will raise! 🙂
I've assumed that NBB defaults to a context of ESM. There's no switch for it to behave differently... ?
there's no switch
So this is kind of a repro of what happens in nbb vs vanilla import:
import { createRequire } from 'module';
import { pathToFileURL } from 'url';
const req = createRequire(pathToFileURL('./script.cljs'))
const ws = req.resolve('ws');
const mod = await import(ws);
console.log(mod);
const mod2 = await import('ws');
console.log(mod2);the logging of mod seems different than the logging of mod2, although they are very similar
I think it is because of this:
"exports": {
"import": "./wrapper.mjs",
"require": "./index.js"
},in the package
nbb should find wrapper.mjs
nbb is going through createRequire since that allows you to resolve a module relative to a script
and this allows you to execute scripts from outside the current working dir
Written up as issue 256, just going through your comments above now.
@borkdude Well done for deducing this!
I think I have a solution in branch issue-256 but there are two failing tests
Aha, so the "exports": {in package.json enables ws to deliver to both CommonJS and ES6 targets. I shouldn't have looked at the code then to deduce this.
(amazing how much JS I've learned moving to CLJS...)
ok, pushing a solution now
(to github, not to npm yet)
Amazeballs! partyparrot
publishing 0.7.135 with the fix
I guess some people may find strange corrected behaviour on upgrade... not disputing it's the right course of action.
yes, this is a trade-off, but I prefer correctness over breaking changes ;)
should be available on npm now
Seems to work now
Confirmed it works! Incredible to watch you work.
Thanks a ton. My previous post about abandoning NBB is no longer correct. I'm attempting to use polylithto shim in different libraries for shadow and nbb and get the best of both worlds. Don't see why the majority of code shouldn't be shared. NBB has better stacktraces on load failures, and I can tweak on AWS. Shadow can use (meta ... to show file lines on stacktraces/ ala timbre for local testing.
Glad to be of help
I guess another difference between Shadow and NBB is the treatment of ^:export https://clojurescript.org/reference/advanced-compilation#access-from-javascript. Shadow seems to still be able to put variables in a global scope even for`:target :esm` , at least for the watch command. For NBB this is not available. Not sure if that's what is referred to by
> In development builds however it still exports everything into the global scope via
from https://clojureverse.org/t/generating-es-modules-browser-deno/6116
I was thinking of using this for message passing between mock NPM modules in my test server, but I guess it's not proper as variables will be eradicated from global scope with ES6.
@danielmgerson nbb doesn't emit any .mjs files so export doesn't really make sense
I have a fake @aws-sdk/xxxmodule with JS code that refers back to my server code. Alas won't work with NBB. No biggy, I'll create a polylith component that wraps this differently for aws and my test server. I wish there was a way to test web-socket apiGv2 code locally within local stack. I refuse to require a live stage to test it. hehe.
I think shadow puts things in a global scope because of reloading (and ES6 reloading doesn't work, so this is shadow's workaround)
you can load nbb files from js like this:
import { loadFile } from nbb
await loadFile('src/my_stuff.cljs')Yeah, that's not applicable to my use case. It assumes the calls only go one way.
you can put things in the global context like this:
(set! js/globalThis.foobar x)the global var thing in shadow is only an artifact of development, I wouldn't rely on it
ooh, didn't know about that. Thanks. It's only for test harness code, not for prod code.
ok
And by using js/globalThis I wouldn't be relying on that shadow quirk 😄 Cheers.
@danielmgerson Ah in nbb you have to write:
(set! (.-foobar js/globalThis) 2)
js/globalThis.foobar ;;=> 2