Fork me on GitHub
#shadow-cljs
<
2022-03-23
>
wevrem00:03:00

Should the newly available :as-alias in Clojure 1.11.0 work with Clojurescript in a shadow-cljs setup? And if it isn’t working for me, is it because shadow-cljs is using an older version of Clojure?

thheller05:03:39

it works regardless of clojure version. if it isn't working you are likely on an old version of shadow-cljs.

wevrem15:03:14

Well I’m using [email protected] installed via npm, but none of the dependencies in shadow-cljs.edn say anything about which version of Clojure to use. Do I need to explicitly add Clojure as a dependency there?

wevrem15:03:24

Nope, that doesn’t work, the message says it is ignored and default version is used to ensure compatibility.

thheller17:03:34

shadow-cljs supports this on its own. neither the clojure nor clojurescript version matters. just use it.

Ælfsyg10:04:02

Sorry to necropost, but from my investigations this morning it seems that shadow-cljs supports :as-alias within ns but not within a free-standing (require '[foo.bar :as-alias bar]).

thheller14:04:23

cljs.user=> (require '[foo.bar :as-alias x])
nil
cljs.user=> ::x/foo
:foo.bar/foo

thheller14:04:26

works fine for me

Ælfsyg12:04:56

Could this be caused by something else?

> shadow-cljs info
shadow-cljs - config: /home/ae/src/ablution/cljs/ablu.ui/shadow-cljs.edn
=== Version
jar:            2.17.8
cli:            2.17.8
deps:           1.3.2
config-version: 2.17.8
> shadow-cljs watch app
shadow-cljs - HTTP server available at 
shadow-cljs - server version: 2.17.8 running at 
shadow-cljs - nREPL server started on port 3333
shadow-cljs - watching build :app
[:app] Configuring build.
[:app] Compiling ...
[:app] Build failure:
------ ERROR -------------------------------------------------------------------
 File: /home/ae/src/ablution/cljs/ablu.ui/src/ae/ablution/ui/core.cljs:11:1
--------------------------------------------------------------------------------
   8 |             [ae.ablution.address.interface.spec :as a.spec]
   9 |             [ae.ablution.ui.views :as views]))
  10 |
  11 | (require '[foo.bar :as-alias bar])
-------^------------------------------------------------------------------------
null
Only :as, :refer and :rename options supported in :require / :require-macros; offending spec: [foo.bar :as-alias bar] at line 11 ae/ablution/ui/core.cljs
--------------------------------------------------------------------------------
  12 |
  13 | (defn ^:export init
  14 |   []
  15 |   (router/start!)
--------------------------------------------------------------------------------

thheller12:04:08

you cannot use require there. that needs to be part of the ns :require

thheller12:04:14

require otherwise only works in the REPL

Ælfsyg13:04:52

Do you mean for Clojure in general, Clojurescript, or Shadow-CLJS?

thheller16:04:28

that doesn't do what you think it does and has been shown to create many more problems than it solves

thheller16:04:52

just do (ns foo.bar (:require [other.foo :as x] [other.bar :as-alias y])) and done

thheller16:04:25

don't try to get creative with require ouside ns that ultimately doesn't end up working

Ælfsyg17:04:19

Fair. Thank you for your work!

bbss08:03:47

Thank you for defclass ! I had been struggling with js/Reflect.construct gobj/extend js/Object.create js/Object.assign (.call Class this props) and nothing seemed to go the way I wanted. At first defclass also seemed to not work but figured it out just fine eventually!

👍 1
wombawomba11:03:05

So I'm using an NPM module — https://github.com/react-syntax-highlighter/react-syntax-highlighter — for syntax highlighting, which has built-in support for two different syntax highlighters (Prism.js and Highlight.js). Taken together, these highlighter packages together with all their supported languages are quite weighty — over 1MB of built code. To avoid pulling in stuff I'm not using, I'm using PrismLight (as described under "Light Build": https://github.com/react-syntax-highlighter/react-syntax-highlighter#light-build), which is meant to only pull in Prism.js itself plus languages that are explicitly specified. Yet, both Prism.js and Highlight.js, together with all the supported languages are included in my shadow-cljs build output. What can I do to avoid this?

thheller19:03:10

this is all relying on non-standard features specific to webpack

thheller19:03:21

so it will only work properly when using that

wombawomba20:03:35

@U05224H0W any advice on how to use webpack to sort this out? I tried using option #2 at https://code.thheller.com/blog/shadow-cljs/2020/05/08/how-about-webpack-now.html, but this still seems to cause the entire package to be included (I believe the relevant line in the output target/index.js is ALL["react-syntax-highlighter"] = require("react-syntax-highlighter");)

thheller20:03:42

not supported

wombawomba20:03:56

sorry, what is not supported? 🙂

wombawomba20:03:05

using webpack to fix this?

thheller20:03:14

you can try requiring whatever you need directly

thheller20:03:38

look at the files in node_modules/react-syntax-highlighter

thheller20:03:49

it likely is just a bunch of files with re-exports

wombawomba20:03:57

yeah I'm actually doing that now

thheller20:03:44

(:require ["react-syntax-highlighter/dist/cjs/prism-light.js"]) or so

thheller20:03:52

dunno about the rest though

thheller20:03:30

this is fully supported (loading the specific languages I mean)

thheller20:03:08

just never require the full react-syntax-highlighter package

wombawomba20:03:05

hey that worked, thanks!

wombawomba20:03:14

@U05224H0W while I have your attention, do you think it would be possible to use the "Async Build" option described at https://github.com/react-syntax-highlighter/react-syntax-highlighter#async-build with shadow-cljs, or do something similar?

thheller20:03:35

do something similar yes

thheller20:03:50

regular code splitting and loading the languages you need in the extra modules

wombawomba20:03:08

I mean, I am using code splitting and it's great, but... wouldn't I have to manually create a module for each language?

thheller20:03:29

do you need all of them?

thheller20:03:50

automatic splits are not supported

thheller20:03:05

I guess you could write something to generate a build config for you or a custom :target

wombawomba20:03:07

users should ideally be able to highlight any code they want

wombawomba20:03:36

okay, let's say I wanted to create one module per language—could I do that in shadow-cljs.edn only, or would I create a cljs file for each separate language?

thheller20:03:58

do the languages register themselves on load or do you need to call something?

thheller20:03:07

looks like you need to call something in the example?

thheller20:03:54

if the direct require works you might be able to go with webpack

thheller20:03:26

(:require ["react-syntax-highlighter/dist/cjs/prism-async.js"]) or so

wombawomba20:03:27

AFAICT it should just 'magically' work — somehow it loads languages lazily when you create corresponding reagent components

wombawomba20:03:47

this is kind of over my head though, so I'm not sure from looking at the code how exactly it works

wombawomba20:03:40

you mean I'd use that import with method #2 from your blog post?

wombawomba21:03:35

alright, I tried that and it doesn't seem like webpack does any code splitting automatically

wombawomba21:03:59

I'm trying to see if there's something I need to configure in webpack...

wombawomba21:03:28

the problem seems to be that the prism-async thing doesn't actually load languages async

wombawomba21:03:42

anyway, I think I might try using shadow-cljs to split the languages out as modules myself

wombawomba21:03:58

seems like a fun exercise

wombawomba21:03:31

@U05224H0W is there any support for writing code to generate a shadow-cljs config? or to merge config from multiple files? (so I don't have to clutter up my current shadow-cljs file)

wombawomba00:03:15

eh nevermind, I typed it out and it wasn't too bad

thheller06:03:42

yes, webpack also needs to be setup to code split. and the async loading can only work if the bundler (ie. webpack) bundled the code accordingly. in webpack this is done via dynamic import in the code. in the closure compiler things are configured via :modules statically.

thheller06:03:35

no you cannot generate the config with the default targets. but you could create a "wrapper" target that generates config in CLJ code and then just delegates to the regular :browser target or so. this is non-trivial and will require digging fairly deep into the internals of shadow-cljs though 😛

wombawomba17:03:22

fwiw setting up dynamic language loading with shadow-cljs was pretty straightforward

wombawomba17:03:57

shadow.lazy helped a bunch

wombawomba17:03:49

the only annoying part was that some of the language packs turned out to depend on other language packs (so I had to set up dependencies between modules accordingly)

wombawomba11:03:54

...also, would it be possible to use the "Async Build" (https://github.com/react-syntax-highlighter/react-syntax-highlighter#async-build) with shadow-cljs?

emil0r11:03:44

Does anyone have problems with tick for release compilation? With :simple optimizations I get

java.time.OffsetDateTime = java.time.goog$module$goog$object.get(module$node_modules$$js_joda$core$dist$js_joda, "OffsetDateTime");
java.time.OffsetTime = java.time.goog$module$goog$object.get(module$node_modules$$js_joda$core$dist$js_joda, "OffsetTime");
module$node_modules$$js_joda$core$dist$js_joda lacks both OffsetDateTime and OffsetTime. Currently running on 5.2.0 for @js-joda/core , and they should be there from what I can tell. All other modules are existing

emil0r12:03:17

I suppose this speaks volumes about how much I trust shadow-cljs o_O. rm -rf node_modules && npm i solved the problem

kennytilton14:03:23

Does shadow have the equivalent of the leiningen checkouts folder usage? ie, some way I can edit a library and have the changes picked up on the next build without installing? Working on my mxWeb Trainer app I am coming up with tweaks for Matrix and mxWeb often enough that that would grease the skids a bit. Not that a local deploy install is the end of the world. (They are leiningen projects.)

Pepijn de Vos16:03:20

Ohh how does your local deploy solution work? I am also developing a library in parallel to my app, and so far I'm just doing extensive testsing and Clojars releases. Would be nice to short circuit that a bit.

thheller19:03:14

shadow-cljs.edn alone does not have checkouts support no

thheller19:03:26

but if you use lein to manage dependencies then checkouts works just fine

thheller19:03:31

same with deps.edn

kennytilton19:03:26

Big caveat @UPHKPR2A3: I know little about CLJ tooling! Anyway... My two changing dependencies are lein projects, so I can do lein install and have either refreshed in a few seconds. The bad news is, I still have to reboot the shadow watch and server to pick up the changed jar. Unless I am missing something. And I do not know if you can take advantage of lein install, or if shadow has the equivalent. This, however, looks encouraging: https://shadow-cljs.github.io/docs/UsersGuide.html#publish-lein And there may well be a simpler shadow command the cognoscenti can provide.

thheller19:03:46

again .. just use lein. with all the features it provides.

kennytilton21:03:11

"just use lein" Sounds like heaven. I did not realize that would work. To me the build process is a mystery, esp. because I did not come from a Java/JAR/Maven background. I just find "starter" projects for a given build tool, or for leiningen do lein new app, and get on with my coding with my fingers crossed. Does "just use lein" mean: • create a minimalist project.clj as documented in https://shadow-cljs.github.io/docs/UsersGuide.html#publish-lein • then lein deps will Do the Right Thing? Including maintaining, pom.xml, I see? • or is it just for lein deploy clojars? • will checkouts work automagically as long as I run lein deps after a change to the contents of checkouts? Thx!

thheller06:03:50

you use lein as you normally do. so you put your :dependencies and :source-paths in project.clj. then add the checkouts you want to that project. then you also add the thheller/shadow-cljs dependency to that project.clj.

thheller06:03:44

in shadow-cljs.edn you set :lein true or :lein {:profile "+cljs"} (if you use a leinigen profile)

thheller06:03:27

that will make shadow-cljs use lein to create the classpath and launch the JVM. so since lein is in charge checkouts just work

thheller06:03:22

this is not a about publishing so you are looking at the wrong piece of the docs

kennytilton14:03:58

Yeah I was in the wrong section, and now that I see it don't know how I missed it! Thx for your patience!

Ryan15:03:09

How does one upgrade shadow-cljs to use clojurescript 1.11.4? Dying to use the :as-alias in requires

Ryan15:03:56

I don't seem to have an explicit dependency in shadow-cljs.edn

Ryan15:03:08

Is it that you wait until there's a shadow-cljs version built with 1.11.4 and it handles itself?

thheller19:03:07

it has been available for months in shadow-cljs

thheller19:03:18

you need no new clojurescript or clojure version for this

thheller19:03:26

just a relatively recent shadow-cljs version

thheller19:03:11

also note that there is no cljs release with :as-alias support yet. 1.11.4 is not it.

thheller19:03:19

but as I said .. not required. it just works already.

wevrem01:03:15

@U020G0VEL75 I was having some trouble with this same thing earlier, and it turned out that even though I had the latest version of shadow-cljs installed locally in my project, I was invoking the global install of shadow-cljs at the command line, and that global install was quite old. I updated the global install, and also changed my habits to invoke the local install going forward.

danielcompton18:03:10

Is there a way to create a “vendor” module which includes all 3rd party dependencies? Would be helpful in reducing load times for very large CLJS apps. Like https://blog.jakoblind.no/code-split-vendors-with-webpack-for-faster-load-speed/

thheller18:03:04

possible yes, helpful unlikely. better to properly split your code so parts no used initially aren't loaded in the initial download

thheller18:03:12

splitting all 3rd party libs likely won't help since it'll still load all of them together anyways then

danielcompton18:03:42

Was that sample project published anywhere? I can’t see the source to lazy-component ?

thheller18:03:06

link is in the intro yes

danielcompton18:03:17

Would be helpful in the sense that the vendored bundle will not get cache-busted as often as the app

thheller18:03:24

due to how :advanced works that very rarely works

thheller18:03:02

you can go with option #2 described here and actually use webpack https://code.thheller.com/blog/shadow-cljs/2020/05/08/how-about-webpack-now.html

thheller18:03:11

that effectively is a vendor bundle all on its own

thheller18:03:34

still has the problem of loading all npm dependencies at once which is rarely what you want