Fork me on GitHub
#shadow-cljs
<
2022-04-14
>
orestis03:04:14

I've made a CLJS library that I distribute via deps.edn, and I now need to add a JS dependency to it. That is, you can't use the library unless you have in your local package.json a specific package. Is there any way to do that automatically, or do I just have to document it?

Aron03:04:20

seems like you need to distribute package.json as well, why is that an issue?

orestis04:04:26

There is a package json in the library but it's not being picked up by the consuming project.

orestis04:04:59

The consuming project uses deps.edn + git sha, so that may be the issue.

Aron04:04:12

I am sorry, I got very confused now. Library needs js dependency but it's not being picked up by the consuming project?

Aron04:04:46

maybe more specifics would help:)

thheller05:04:56

@orestis you can put a deps.cljs with {:npm-deps {"that-package" "version"}} on the classpath of the lib. that'll tell CLJS about the npm dependency and install it

1
orestis06:04:40

Hehe fair enough @Aron - reseda used to be pure CLJS, depending on React only but since any user of Reseda already has react there was no point in trying to install it. I've updated Reseda to be React 17/18 compatible and now it needs use-sync-external-store from npm. I will try what @thheller suggested and report back

tugh17:04:08

We've just migrated our project from figwheel-main to shadow-cljs. We were using :css-dirs setting of figwheel-main for CSS hot reload but we don't have CSS hot reload with shadow-cljs now, probably due to incorrect config. We're not using the dev http server of shadow-cljs. We're serving our HTML/CSS/JS with the CLJ application. We get the updated css with page refresh but it doesn't hot reload. Below is our shadow-cljs config(truncated):

{:builds {:app {:target :browser
                :output-dir "frontend/public/js"
                :asset-path "/js"
                :devtools {:watch-dir "frontend/public"}}}}
And here is the directory structure of our codebase(truncated):
frontend/
└── public
 ├── css
 │ ├── main.css
 │ └── main.css.map
 └── js
 ├── app.js
 ├── app.js.map
 ├── cljs-runtime
 └── manifest.edn
resources/public/
├── css
│ ├── animations.less
│ ├── mixins.less
│ ├── variables.less
│ └── etc...
├── extra
├── fonts
├── img
└── js
frontend and resources dirs lives under the app dir on the same level and both of them are in the classpath. Another process automatically compiles less files under resources/public/css and outputs to frontend/public/css/main.css. Can you point out what is wrong with my config?

tugh17:04:18

BTW, path to CSS file in link tag is absolute:

<link href="/css/main.css" rel="stylesheet preload" type="text/css"  as="style" />

thheller17:04:08

looks fine. note that :watch-dir currently only applies when the watch is started. so if you made adjustments while it was running they might not be active

thheller17:04:20

it needs to be rel="stylesheet". preload should be a separate tag? didn't even know you are allowed to combine them?

1
tugh17:04:06

Oh, thank you! Removing preload fixed it. I'd never thought this was the problem

tugh17:04:39

I don't know if it is valid too. This code is older than me in the company and I don't know the reason why it is there

thheller17:04:22

yeah seems kinda redundant. I mean by the time the parser finds the tag it can load the css file directly. no need to first preload it?

tugh18:04:22

Decided to remove preload. Really appreciate the help! ✌️

niquola21:04:59

Hi, i have multiple apps in project - can i compile them in parallel?

thheller04:04:42

you can have multiple builds running at the same time yes. shadow-cljs watch app1 app2 app3 same for all other commands

thheller04:04:05

release will not be parallel, watch will be

niquola05:04:18

I mean releases - we have 6 apps from same source, it takes 10 min to build - want to speedup it

thheller05:04:03

I made the default sequential since parallel was overloading some systems

thheller05:04:26

you can make your own release function and run them in parallel

thheller05:04:14

so just a function (defn release [& args] (shadow/release! :foo) (shadow/release! :bar) ...)

thheller05:04:19

that would be sequential

thheller05:04:29

you can use (future (shadow/release ...)) to start it in a thread

thheller05:04:35

or use a thread pool

niquola22:04:29

Thank you!

Jorge Barreto22:04:54

As a proof of concept, I'm trying to import a CLJS component into a CRA React app. My shadow-cljs config:

{:source-paths ["src"]
 :dependencies []
 :builds {:code {:target :npm-module
                 :output-dir "node_modules/shadow-cljs"
                 :entries [app]}}}
src/app.cljs:
(ns app)
(defn ^:export hello [] "Hello World!")
src/App.js:
import { hello } from "shadow-cljs/app";
but i get the following error: Uncaught ReferenceError: process is not defined the culprit appears to be the compiled cljs_env.js:
var CLJS_GLOBAL = process.browser ? (typeof(window) != 'undefined' ? window : self) : global;
any insight into what i might be missing here?

rayat22:04:31

Interesting! As a hack, you could use one those CRA-patching libs to add a Define plugin to webpack, with process defined with whatever you need it to be, this will at least let it compile Though I'm very curious as to why it's not already defined and what that means for the evaluation of cljs_env.js

Jorge Barreto22:04:07

I could probably use craco to accomplish something like that, but I assume shadow-cljs needs values that are populated in there? It looks to be defined in cljs.core.async.js:

var process = (function (p__14390){...

Jorge Barreto22:04:36

I agree, it's curious that it's not already defined

rayat00:04:57

Yes, craco was what I was referring to. This is most certainly not at all a fix, but perhaps an unblocker to investigate or debugger further, apologize if I implied otherwise, and also apologies if this was a useless suggestion! Please do update this with anything you find, would love to know wtf is going on. Is that cljs_env.js file imported or loaded in particular way? I am not sure how it is able to depend on a global reference that is undefined at runtime. I have not personally looked at shadow's source code. However, I wonder if: 1. This has something to do closure compiler/libs bespoke module loading system interacting weirdly with cra/webpack 2. This has something to do with your setup in particular. Is the example code you've posted actually the minimum reproducible source code - ie, what you've seen this issue come up in?

Jorge Barreto01:04:25

I can try craco next -- I'm certainly at a wall otherwise. But no apologies needed! 🙂 I'm very happy to receive all the help I can get. I have been suspecting that the interaction with webpack is somehow to blame here.. As far as the code, the only thing I haven't shared is the results of yarn create react-app. I can put together a small minimal reproduction and commit it somewhere if it would be of interest. To answer your first question, I have been going on https://shadow-cljs.github.io/docs/UsersGuide.html#target-npm-module. In part they read: > If you use the default :output-dir of "node_modules/shadow-cljs" you can access the declared namespaces by using require("shadow-cljs/demo.foo") in JS. I'm not quite doing that, as I have import statements instead. Doing import { hello } from "shadow-cljs/app" leads to the error because the compiled app file has a require('cljs_env.js')

Jorge Barreto01:04:49

Frankly, I can tell I'm going about this all wrong but I'm not yet sure on how to right it

thheller04:04:43

:target :npm-module by default assumes a node runtime. so add :runtime :browser to the build config. that should remove that reference to process

Jorge Barreto12:04:21

I tried that as well, unfortunately the reference to process is still there

Jorge Barreto12:04:14

I have a minimal reproduction here: https://github.com/jorge-barreto/cljs-in-cra.git The build config now reads:

;; ;; shadow-cljs configuration
{:source-paths ["src"]
 :dependencies []
 :builds {:code {:target :npm-module
                 :runtime :browser
                 :output-dir "node_modules/shadow-cljs"
                 :entries []}}}
If there is any further insight on what is going on here, I'd really appreciate it 🙃

thheller14:04:53

FWIW :target :esm is probably a better choice these days regarding interop. https://clojureverse.org/t/generating-es-modules-browser-deno/6116

thheller14:04:09

I'll check your repro later though

thheller14:04:41

if you are integrating with CRA add :js-options {:js-provider :import} to the build config

Jorge Barreto15:04:56

There's no rush! I really appreciate the time. I tried adding the :js-provider to no avail. I'll try :target :esm next

thheller15:04:02

:js-provider was meant for :target :esm sorry

👍 1
Jorge Barreto16:04:04

Ok, I can confirm that :target :esm works, but only when run as shadow-cljs release . build and watch produce many build errors for webpack. I'll push soon to a branch on the repo

thheller16:04:44

what kind of error?

Jorge Barreto16:04:31

couple thousand lines across many files, looking like this:

src/generated/cljs-runtime/cljs.core.async.impl.buffers.js
  Line 2:1:      'goog' is not defined  no-undef
  Line 3:1:      'cljs' is not defined  no-undef

thheller16:04:18

hmm odd. I'll take a look if you push that to the repo

Jorge Barreto16:04:07

you can take a look in the target-esm-dev branch: git clone -b target-esm-dev

thheller16:04:44

ugh just checked. guess webpack got a lot stricter since the last time I tested this

thheller16:04:02

it doesn't recognize that these are things on globalThis and actually do exist

thheller16:04:33

this looks like a linter error though. maybe that can be turned off?

thheller16:04:54

the code is actually fine

Jorge Barreto16:04:07

yes! nice catch -- that works

👍 1
Jorge Barreto17:04:51

i updated the repo w/ the working code. i really appreciate the help with this!

🎉 1
jdf17:06:47

hi. I’m following along on this thread since I’m trying to embed an existing cljs app into a react container. I’m successful in releasing the app with :target :esm but I get errors when I try to import it in the react app. I’ve tried including :js-options {:js-provider :import} but the compilation process fails when I do claiming the namespace react is not available when required by reagent/core.cljs. Have any of you encountered a similar error by any chance?