This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-06-16
Channels
- # ai (1)
- # announcements (3)
- # architecture (14)
- # aws (1)
- # babashka (8)
- # beginners (62)
- # biff (27)
- # calva (14)
- # clerk (6)
- # clj-kondo (6)
- # cljsjs (1)
- # clojure (59)
- # clojure-austin (1)
- # clojure-europe (15)
- # clojure-gamedev (5)
- # clojure-norway (246)
- # clojurescript (3)
- # community-development (5)
- # cursive (4)
- # data-science (6)
- # datomic (90)
- # events (1)
- # lambdaisland (1)
- # lsp (20)
- # matrix (1)
- # meander (6)
- # music (1)
- # off-topic (59)
- # pedestal (2)
- # releases (3)
- # shadow-cljs (90)
- # specter (6)
- # tools-build (5)
- # tools-deps (5)
- # xtdb (11)
@thheller apologies in advance if this already has been discussed … I feel I’ve got a little lost in the woods reading the docs when working with esm modules :s … I’ve been playing with this old https://gist.github.com/borkdude/7e548f06fbefeb210f3fcf14eef019e0 as wanted to try using the https://github.com/vadimdemedes/ink library too which has been totally rewritten as an esm only module now
i have a similar shadow-cljs config:-
;; shadow-cljs configuration - use lein to manage dependencies and the classpath etc
{:lein true
:builds {:cli {:target :esm
:output-dir "out"
:runtime :node
:modules {:index {:init-fn cli.core/main}}
:js-options {:keep-as-import #{"ink"}}}}}
and my cli.core namespace requires the “ink” module referring to the render fn and Text component
(:require
["ink" :as ink :refer [render Text]]
...
this all works perfectly when I build a release, but when running a dev/watch I get the following error:-
file:///Users/benj/Development/fireadmin_2.0/out/cljs-runtime/shadow.esm.esm_import$ink.js:3
shadow.esm.esm_import$ink = esm_import$ink;
^
ReferenceError: esm_import$ink is not defined
at file:///Users/benj/Development/fireadmin_2.0/out/cljs-runtime/shadow.esm.esm_import$ink.js:3:29
at ModuleJob.run (node:internal/modules/esm/module_job:194:25)
is this a result of the compiler renaming the “ink” symbol and is there anything I can do about it?what is the context here? does it happen when you first run the output? does it happen over the REPL?
it’s as result of compiling or watching a dev build - as soon as i run my script:-
$ node ./out/index.js
if I perform a release build, the same command works finesince I’m using leiningen to manage the dependencies i start a dev build with the following:-
lein with-profile +dev run -m shadow.cljs.devtools.cli --npm watch cli
and building for release:-
lein with-profile +live run -m shadow.cljs.devtools.cli --npm release cli
i also appreciate this is a little vague so am happy to put a little github repro together … just from what I’ve been reading and trying to get through my thick skull is whether it’s due to the :keep-as-import bit which might exclude it for development builds but happily bundle it for release builds? i must admit i struggle with the complexities of esm vs common js etc … this is the first time I’ve tried to build a simple project using a dependency that’s esm only :s - i really do appreciate any help but also understand you’re insanely busy!
since its node you can just run :js-options {:js-provider :import}
maybe that fixes it?
latest version i believe - i'll give the js-options a try and if no joy i'll get a repro for you :) thanks for the continued help
oh ... i might not actually need it but the project is eventually meant to connect to one of our various firebase projects and i was attempting to use different profiles to add additional src paths for the various google service json files
(and i needed to use leiningen as that supported connecting to our private maven repo on google cloud)
ok, just tried with :js-provider :import and it’s the same deal, if I build a release then my script runs fine, if I compile/watch a dev build i get the same ReferenceError: esm_import$ink is not defined
error 😞
i’ll get a repro to you, if not over the weekend then definitely Monday!
https://stackoverflow.com/questions/35551366/what-is-the-defined-execution-order-of-es6-imports
however, ink
has a top level async import
, which then apparently makes everything async and totally messes the loading order of shadow-cljs
ah fair enough @thheller - really appreciate the update especially over the weekend! i think for the time being I could at least go back to a pre 4.0 release of ink (prior to the esm module rewrite) - it’ll mean I can’t use react 18, but that’s not an issue at all really
oh nice - that’s encouraging! if there’s anything I can try and do to help? although the various ways commonJS and esm work and conflict with each other currently confuse me!
just need to tweak the output thats generated so node is happy. just need to find a way to work around one last issue
legend! that’s dev and release builds working … am I right in that I shouldn’t be loading this module dynamically, I should be able to (:require [“ink” :as ink :refer [Text render]]) .. as normal?
just spotted one little issue which might be due to hot reloads in dev builds … if I change my code and run my script again I get:-
file:///Users/benj/Development/fireadmin_2.0/out/cljs-runtime/shadow.esm.esm_import$ink.js:4
import * as esm_import$ink from "ink";
^^^^^^^^^^^^^^^^^^^^^^^^^^
SyntaxError: Identifier 'esm_import$ink' has already been declared
at ESMLoader.moduleStrategy (node:internal/modules/esm/translators:119:18)
at ESMLoader.moduleProvider (node:internal/modules/esm/loader:468:14)
you say hot reload and then "run my script again", so what is it? a hot-reload or node that-script.js
?
Sorry … the script just renders a Text component to the terminal and then exits. If I simply change the color property on the text component, the watch process recompiles and produces new output - then I run the script again and get the error. If I restart the watch, and run my script it all works fine
the change I made is not cache aware, so it just writes it every time and duplicates the imports
pleasure … and thank you for all your hard work on shadow - it’s been a game changer for me!
@thheller sorry, it’s me again … not a big issue - dev build is still happy etc, but I can’t get a REPL connection with a :target :esm build - previously it was :node-script and this was fine - now I just get repeated Waiting for Shadow CLJS runtimes, start your CLJS app
even though my node script is running? Don’t want this to be a time sink so if the :esm target doesn’t support connecting via a REPL then fair enough
REPL in general is very tricky with ESM, so have to figure some stuff out for that eventually
kk no worries … wish I hadn’t started playing around with this “ink” library now … will see how far I get without my REPL crutch 😄
you could just stick with a regular :node-script
and use a dynamic import to load the ink
lib
oh! this?
(ns
(:require
[shadow.esm :refer (dynamic-import)]
[shadow.cljs.modern :refer (js-await)]))
(defn foo []
(js-await [mod (dynamic-import "ink")]
(js/console.log "loaded module" mod)))
?
erm, do I just then require it in any of my namespaces that need it as normal afterward?no you need to expose mod
somehow to the outside and make sure the import finishes before you run anything else
for shadow.esm to work you probably need :prepend "global.shadow_esm_import = function(x) { return import(x); }"
in the build config
well that all works a treat! back to :node-script target with REPL, using the pesky ESM ‘ink’ module … script waits until the dynamic import has completed at which point it (set!’s …) all the stuff I need to expose, then I just require my new ink namespace instead and :refer to everything as normal … brilliant!
I should probably make that a properly documented recommendation. going full ESM so full of so many problems 😛
😄 … the Javascript eco system (common Js and ESM) makes my brain hurt … if it wasn’t for shadow-cljs I’d be in a proper state :s
hey @thheller - one more quick question, if i needed to import another esm module what would i change my :prepend to in my build config? i currently have
"global.shadow_esm_import = function(x) { return import(\"ink\"); }"
which works well, would I need to create my own js object and merge the results of multiple imports together e.g.
var ink = import("ink");
var other = import("other");
return merge(ink, other) // whatever the js equivalent is :)
:target :esm
sets up that alias automatically, but :esm
then just has other problems which you are aware of 😛
is there an easy way for me to profile the compiler? for some reason one ns takes nearly 30s to compile, and I want to figure out why
i don't know of a flamegraph but the shadow cljs console usually reports how long it took to write out cljs files. i assume this ia your bottleneck and not closure's optimizations
misread your post, oops
otherwise profiling is just regular profiling. nothing special in regards to the compiler. if you suspect macros just record time spent in anything but cljs.*
or shadow.*
. that should reveal macro issues
did you try to just eval form for form in the REPL? should be noticable if something is slow
I haven't gone form for form. the curious thing is that in another build, a change to the file takes 5s. so my hypothesis that it's a form in the file might be off.
it could be a difference in the build type too. one build is an :npm-module
the other is a regular :browser
build
build targets really only control how the output is organized. they are not a factor in actual compilation. in fact they aren't involved in that code.
so, more than likely it is the macros. what is done within those I cannot say. if you have something looking at the target setting that is certainly possible
I'm guessing it's macro BS but it would be nice to be able to easily confirm that with a flamegraph
I had moderate success at profiling Clojure using YourKit https://www.yourkit.com/java/profiler/features/