Fork me on GitHub
#clojurescript
<
2021-04-10
>
Timofey Sitnikov11:04:05

Good Morning Clojurians, I am doing some cljs with shadow-cljs and my main.js file is 20 mega bytes and every time I update something it takes 30 seconds to re-compile, is that normal for cljs?

p-himik11:04:54

Too few details. 20MB should be normal during development if you use a lot of and/or heavy third-party libraries (probably NPM). But it's not normal for a release bundle. 30 seconds is normal for a release build or for the initial debug build. It's not normal to wait 30 seconds for an incremental compilation step during watch.

4
simongray11:04:31

try #shadow-cljs and post your shadow-cljs.edn file

Timofey Sitnikov11:04:15

@U4P4NREBY my shadow-cljs.edn file:

{:deps   {:aliases [:dev]}
 :nrepl  {:port 9000}
 :builds {:main       {:target     :browser
                       :output-dir "resources/public/js/main"
                       :asset-path "/js/main"

                       :modules    {:main {:init-fn app.client/init}}
                       ;; guardrails checks only during dev
                       :dev {:compiler-options
                             {:external-config
                              {:guardrails {:emit-spec? true :throw? false}}}}

                       :devtools   {:after-load app.client/refresh
                                    :preloads   [com.fulcrologic.fulcro.inspect.preload app.development-preload]}}

          :test       {:target           :browser-test
                       :test-dir         "resources/public/js/test"
                       :ns-regexp        "-test$"
                       ;; static required for mocking to work
                       :compiler-options {:static-fns      false
                                          :external-config {:guardrails {:throw? true}}}
                       :devtools         {:http-port          8022
                                          :http-resource-root "public"
                                          :http-root          "resources/public/js/test"}}

          :ci-tests   {:target           :karma
                       :js-options       {:js-provider :shadow}
                       :compiler-options {:static-fns      false
                                          :external-config {:guardrails {:throw? true}}}
                       :output-to        "target/ci.js"
                       :ns-regexp        "-test$"}

          :workspaces {:target     nubank.workspaces.shadow-cljs.target
                       :ns-regexp  "-(test|ws)$"
                       :output-dir "resources/public/workspaces/js"
                       :asset-path "/workspaces/js"
                       :devtools   {:preloads           [com.fulcrologic.fulcro.inspect.preload]
                                    :http-root          "resources/public/workspaces"
                                    :http-port          8023
                                    :http-resource-root "."}}}}

p-himik11:04:23

@U012GN57FJ9 If 20MB is the release build, then you can use this to understand what inflates the bundle: https://shadow-cljs.github.io/docs/UsersGuide.html#build-report

Timofey Sitnikov11:04:19

No, 20 mb is development build.

p-himik11:04:56

Then it's perfectly normal.

Michaël Salihi13:04:51

Hi! I think I had confirmation that a dynamic import/require like in this example is not possible in CLJS (browser).

const app = document.getElementById('app');

render(
  <InertiaApp
    initialPage={JSON.parse(app.dataset.page)}
    resolveComponent={name =>
      import(`./Pages/${name}`).then(module => module.default)
    }
  />,
  app
);
Someone would have an idea of an alternative solution? I would like to avoid calling Reagent components one by one by hand and have the same level of automatism as in the example given.

Michaël Salihi13:04:42

For now, here's how I do it.

(ns myreagent.core
  (:require ["@inertiajs/inertia-react" :refer [App]]
            [myreagent.pages.home :refer [Home]]
            [myreagent.pages.demo :refer [Demo]]
            [reagent.core :as r]
            [reagent.dom :as d]))

(def el (.getElementById js/document "app"))

(defn home-page []
  [:> App {:initial-page (.parse js/JSON (.. el -dataset -page))
           :resolve-component (fn [name] (r/reactify-component (case name
                                                                "Home" Home
                                                                "Demo" Demo)))}])

(defn mount-root []
  (d/render [home-page] el))

(defn ^:export init! []
  (mount-root))

p-himik13:04:37

Module splitting, probably. But use it sparsely and only for isolated chunks of functionality. I.e. there's very little reason to split the main page with 10 panels into 10 modules if all the panels will be displayed at the same time unconditionally anyway.

Joseph Rollins14:04:52

I'm having trouble using shadow-cljs. I have a basic build:

{:fn {:target :node-library
       :compiler-options {:infer-externs :auto}
       :output-to "functions/index.js"
       :exports-var functions.fn/exports}}
Yet it complains required namespace "functions.fn" is not available but I have src/functions/fn.cljs with:
(ns functions.fn
  (:require ["firebase-functions" :as functions]
            ["firebase-admin" :as admin]))

(defonce init (.initializeApp admin))

(defn echo [req res]
  (js/console.log req res))

(def exports
  #js {:echo (.onCall functions/https echo)})
I assume i'm missing something pretty trivial but I cannot figure it out. It was trivial -- I needed my file to be at src/main/functions/fn.cljs

3
ribelo20:04:58

Should't transit save metadata?

(write-transit (with-meta {:a 1} {:b 2}))
;; => "[\"^ \",\"~:a\",1]"
(meta (read-transit (write-transit (with-meta {:a 1} {:b 2}))))
;; => nil

djblue20:04:10

The key is :transform write-meta

djblue20:04:39

If you are also using transit-clj, watch out for this issue https://github.com/cognitect/transit-clj/issues/47

alexmiller20:04:51

no, transit does not preserve metadata

alexmiller20:04:10

it's designed to be language agnostic and that's not a feature generally available

ribelo20:04:11

I found such a line in the code and I was convinced that it saves metadata https://github.com/cognitect/transit-cljs/blob/master/src/cognitect/transit.cljs#L195

alexmiller20:04:00

looks like maybe the transit-clj / transit-cljs libs do have an optional transform for it

alexmiller20:04:53

in transit-cljs, http://cognitect.github.io/transit-cljs/cognitect.transit.html#var-writer takes a :transform, and write-meta is an available transform

💯 6
alexmiller20:04:06

so, I take it back, it does support it (if asked)!

ribelo20:04:46

@djblue already told me this solution in the thread

ribelo20:04:39

metadata is probably one of the most underrated feature

☝️ 3
djblue20:04:10

Especially with how you can implement protocols via metadata!

ribelo20:04:21

I haven't tried this yet, but it sounds great.

djblue20:04:31

It's particularly useful for implementing clojure.core.protocols/nav on your https://github.com/djblue/portal/blob/master/src/examples/hacker_news.cljc#L76-L80 which allows tools to help you navigate through your data.