Fork me on GitHub
#shadow-cljs
<
2023-07-20
>
Hendrik06:07:58

I am facing issues with advanced compilation. It renames things which causes the program to fail at runtime. I am using three.js. In this snippet (camera is an instance of three/Camera class):

#?(:cljs (defn set_camera [camera pos target]
           (let [{px :x py :y pz :z} pos
                 {tx :x ty :y tz :z} target]
             (set! (.. camera -position -x) px)
             (set! (.. camera -position -y) py)
             (set! (.. camera -position -z) pz)
             (.lookAt camera tx ty tz)
             (.updateProjectionMatrix camera))))
This gets compiled to:
function aT(a, b, c) {
        var d = ah(b);
        b = xe.o(d, Jx);
        var e = xe.o(d, Gx);
        d = xe.o(d, Hx);
        var f = ah(c);
        c = xe.o(f, Jx);
        var h = xe.o(f, Gx);
        f = xe.o(f, Hx);
        a.position.x = b;
        a.position.y = e;
        a.position.z = d;
        a.Gf(c, h, f);  // fails here with a.Gf is not a function
        return a.cf()
    }
The strange thing is that .lookAt and .updateProjectMatrix method calls where renamed, but position attribute was not. How can I stop advanced compilation from renaming these methods?

thheller06:07:17

you should be getting externs inference warnings for these? what you need is externs, to prevent the renaming

thheller06:07:31

so in the above (defn set_camera [^js camera pos target] should be all you need

thheller06:07:19

from https://github.com/HendrikLevering/electric_three_demo/blob/main/shadow-cljs.edn#L7-L8 I'm guessing you chose to ignore warnings instead of dealing with them 😛

Hendrik07:07:29

The ^js tag did the trick. Thank you so much 🙂 Honestly I didn’t look at the warnings settings. I used the electric starter app as a base and didn’t pay attention to the settings

Rachel Westmacott10:07:52

Not sure what I'm doing wrong. I've read the docs on CSS reloading (even when using your own server) and I can't seem to make it work.

Rachel Westmacott10:07:23

When I update my css file the changes propagate to /target/site/assets/styles.css and the watch process says

sending incremental file list
assets/
assets/styles.css
(that's from an rsync process I have running in a package.json watch command)

Rachel Westmacott10:07:04

shadow-cljs.edn looks like

{:deps   {:aliases [:ui]}

 :nrepl  {:port 8778}

 :http   {:port 8080
          :host "localhost"}

 :builds {:app {:target     :browser
                :output-dir "target/site/assets"
                :asset-path "/assets"
                :devtools   {:watch-dir "target/site/assets"
                             :watch-path "/assets"}
                :modules    {:core {:init-fn <project>.ui/init}}
                :release    {:compiler-options {:warnings-as-errors true}}}}}

Rachel Westmacott10:07:39

but the browser doesn't seem to know that anything has happened and doesn't seem to make any calls to the server I'm running. (by contrast if I manually hard refresh the page it asks for a bunch of resources from my server)

thheller10:07:46

the relevant piece that is missing here is your http server config

thheller10:07:09

from the setup I'd assume that target/site is the "root" dir that is served by the server?

thheller10:07:22

and that you load the files via /assets/styles.css in the HTML?

Rachel Westmacott10:07:26

Yes, I think that's right

Rachel Westmacott10:07:36

<link rel="stylesheet" href="/assets/styles.css" type="text/css">

thheller10:07:46

then your config should be :watch-dir "target/site" and no :watch-path

Rachel Westmacott10:07:59

well that just worked!

👍 2
ccann15:07:41

I have an old project that uses leiningen and figwheel.main that I’m trying to convert over to shadow-cljs. I’m currently trying to compile for the browser. The project has some dev code that reads a template and outputs the index.html file. That seems to work, but the browser throws an error Uncaught SyntaxError: Unexpected token '<' (at main_bundle.js:1:1) and I can see that main_bundle.js is actually an HTML file

:dev-http {8000 {:root "public"
                  :handler co.foo.my.dev-server/handler}}
 :builds
 {:dev
  {:target :browser
   :output-dir "public/js"
   :modules {:main {:init-fn co.foo.my.core/init}}
   :compiler-options {:infer-externs false
                      :warnings {:undeclared-var false}}
   :devtools {:autoload true
              :ignore-warnings true
              :preloads []}}}

thheller15:07:02

the js file will be main.js, so either rename your module or update the html.

ccann16:07:38

thank you

ccann22:07:22

I’m trying to set up webpack with shadow-cljs. I understand I need to add

:js-options
   {:js-provider :external
    :external-index "target/index.js"}
and then invoke webpack to build the target/index.js file and output it into e.g. libs.js and include that with a script tag in my index file. What is the development process like then? Do you run shadow-cljs watch foo and then webpack watch in two separate terminals? sorry if this is a silly question

ccann23:07:48

I have this very minimal webpack config

const path = require('path');

module.exports = {
    mode: "development",
    entry: './target/index.js',
    output: {
        path: path.resolve(__dirname, 'public/js/'),
        filename: 'libs.js',
        clean: true,
    }
};

ccann23:07:24

right now if I try running both shadow and webpack watches independently I just get ReferenceError: shadow$bridge is not defined

ccann23:07:58

oh dang, I figured it out — my <script> tags were in the wrong order… needed to load libs before main

hifumi12323:07:41

I have seen an example repository somewhere out there that uses webpack hot reload, but it’s a pretty bad dev experience in general

thheller06:07:52

for the most part you don't really need webpack hot-reload, unless you change your npm requires frequently

👍 2
thheller06:07:25

if you just want to get some basic dependencies and don't change them often you don't even need webpack watch, just build once and rebuild if you change anything npm related

👍 2
🙏 2