This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
- # announcements (3)
- # babashka (130)
- # beginners (73)
- # calva (22)
- # cider (46)
- # cljdoc (18)
- # cljs-dev (196)
- # cljsrn (18)
- # clojure (255)
- # clojure-europe (2)
- # clojure-finland (8)
- # clojure-gamedev (1)
- # clojure-germany (2)
- # clojure-losangeles (6)
- # clojure-nl (1)
- # clojure-spec (16)
- # clojure-uk (33)
- # clojurescript (32)
- # community-development (1)
- # conjure (40)
- # core-logic (11)
- # cursive (4)
- # datascript (8)
- # devcards (17)
- # emacs (21)
- # exercism (2)
- # fulcro (29)
- # funcool (15)
- # graalvm (18)
- # jobs (17)
- # jobs-rus (1)
- # lambdaisland (1)
- # lumo (1)
- # malli (19)
- # off-topic (15)
- # pathom (22)
- # quil (7)
- # re-frame (3)
- # reagent (3)
- # shadow-cljs (14)
- # spacemacs (41)
- # specter (2)
- # sql (5)
- # tree-sitter (1)
- # unrepl (16)
- # vscode (3)
- # xtdb (11)
- # yada (1)
Oh, works now. I tested different command and left that in the configuration, with proper npx command I see the output file. I think it would be good idea to print out the webpack output?
Though for watch mode it definitely makes sense to not show the webpack stdout. Anyway, I can just run the command myself if I want to see the output, and probably makes more sense here anyway, as I might want to pass the bundle to webpack directly or to Karma.
RE: not showing the webpack output, I think I've made a mistake in my webpack config and it's taken me a good 15m or so to realize that's why cljs is silently not producing output.
Didn't fail, I think I didn't have webpack installed (I guess I wiped my node_modules). And it was prompting for input.
Interestingly, while the bundle output is smaller for react/react-dom, shadow still produces slightly smaller output. (1KiB difference).
For a simple prn, running through webpack seems to save some bytes:
prn/Cljs 1.10.520-fn-invoke-direct.js 90KiB 21KiB 18KiB prn/Cljs 1.10.520.js 92KiB 21KiB 18KiB prn/Cljs 1.10.597-fn-invoke-direct.js 93KiB 21KiB 18KiB prn/Cljs 1.10.597.js 94KiB 21KiB 18KiB prn/Cljs c1cf559a Bundle-fn-invoke-direct.js 90KiB 20KiB 17KiB prn/Cljs c1cf559a Bundle.js 91KiB 20KiB 17KiB prn/Shadow-Cljs-2.8.94-fn-invoke-direct.js 90KiB 20KiB 17KiB prn/Shadow-Cljs-2.8.94.js 92KiB 20KiB 17KiB
For very simple:
I get slightly smaller bundle (by 8 bytes) for the webpack version.
(ns io.dominic.cljs-sizes.main (:require [reagent.dom :as rd])) (defn welcome [name] [:h1 (str "Hello, " name)]) (defonce _mount (rd/render [welcome "Fred"] (js/document.getElementById "app")))
I'm expecting bundle to win because it does not have so many duplicate dependencies as cljsjs creates.
reagent website in fact uses React with node module processing, so React code is going through Closure optimizations
No, React is probably one of the only libs that works and even it still requires the extern file.
Extern file also means that it isn't properly optimized, we should have separate extern file for this, with only the dynamic names that break when optimized, but not the public API which can be optimized in this case.
without the extern file, node module processing output goes down to 453KB (but it doesn't work)
^:export work in advanced optimized bundle, so that the exported fn can be accessed from the JS side? Looks like
goog.global is not the same as
window and looks like it is not seen outside of Cljs module.
Maybe Cljs should set goog.global = window somewhere,
goog.string.unescapeEntities also breaks as it doesn't find
With few inferred extern additions, I now have Reagent tests passing with advanced optimized bundle.
as noted you can easily run the bundle cmd separately and that might be common because you want to do more things
One problem is that I don't understand how bundle relates to development mode at all
Well, I have this "worry" that it'll be run more frequently than just once. So dev would be very inconvenient otherwise.
Bundle-cmd is run after every compile. Or I guess you could use JS tools to watch for file changes.
Okay. One worry I have is webpack failing mid-development session. That would be a bit of face meeting wall to realize/debug.
that possible but I don't think it's much of a worry - you need the bundler when your ClojureScript requires include something from
node_modules you haven't required before.
also nothing is stopping anyone from using watchman and setting this up however they like
@juhoteperi we could change ^:export here,
goog.exportSymbol takes a third parameter - I'm wondering if that's good enough
Closure library code which presumes
goog.global is the window object is also a problem, that wouldn't help with that
@juhoteperi ah yeah, ok we have the hook for this in core, only used in Node.js right now
the "problem" is that
goog.global = this breaks because
this is no longer
window after webpack has processed it
goog.global in cljs.core is also too "late" given that it may have been used before loading
cljs.core by closure code (eg. goog/base.js)
that is used for
:npm-module which is a rather special
:target in that it exposes each CLJS ns as a separate
but I think the next version of webpack will remove the
process polyfill so that would break then
maybe instead of checking for
process.browser the global object could be just window || self || global ?
Yeah, maybe it is best to leave
goog.global intact by default? MAYBE option to set it to something IF webpack or other tools don't have better way handle this. It depends on where the bundle is used, what the global object should be.
Another option instead of mucking around with
goog/base.js - we could just make a new compiler option to set this
@thheller I've never personally seen cases where setting target at the end of core.cljs is a problem - do you have something specific? this after implementing in a bunch of environments, browser, Node, React Native etc.
but it used to be a problem that the
goog/base.js would then be defined in another scope
Webpack has way to set module
@juhoteperi right but this will be different in every bundler - I'm ok w/ having a way to control this because
^:export is critical
draft announcement for the new bundle target - https://github.com/clojure/clojurescript-site/blob/april-release-target-bundle/content/news/2020-04-13-bundle-target.adoc
a lot of the changes/fixes to master were based on a new React Native tool I've been working on for the past three weeks
if you're curious how to leverage
cljs.main and the new build target in a custom build tool - this is worth checking out 🙂
re: krell, very cool. it looks like it doesn’t support hot-loading yet; do you use a REPL workflow atm?
I’m v interested in creating an easy hot reloading experience that takes advantage of the new react-refresh package. It’s a little tricky tho.
react-refresh requires that when changing a file, all files in the dependency tree up to the root will be reloaded. This is to support e.g. changing a function or constant in a file, that gets required by another file, that then gets required and used in a component, will properly invalidate the component and trigger React to re-render that component. figwheel and shadow-cljs typically takes the simpler approach of only reloading the file changed and it’s direct ancestors because we assume everything is in the global scope and that we don’t do side-effects on reload (which react-refresh is essentially a side-effect on reload)
re: REPL - that's mostly what Krell does - REPL stuff - the bundler stuff is just reusing ClojureScript master
I feel like if I could figure out how to handle these react-refresh cases from a REPL, it would make everything else easier
the “side-effect on
defn ” pattern that react-refresh heavily encourages makes it more difficult
the point is you cannot preserve the REPL state - but depending on what you're doing who cares?
the point of auto-reconnect is that you can just follow all the usual React guidelines
yeah, I want to preserve the behavior you get when enabling “Fast Refresh” in React Native
I'm not saying of course that react-refresh works - just saying that's definitely one of things I'm interested in doing different w/ Krell
disabling React refresh should be entirely an optional thing because you want to do a stateful REPL session
I think there’s two kinds of refresh in RN: a full reload of the app bundle on change, and the new “Fast Refresh” feature IIRC
The “Fast Refresh” mode preserves state across reloads - even local component state - but requires you to generate signatures for each component that get invalidated on file change. this is done by a babel plugin that RN gets shipped with, which obviously won’t work with CLJS
a react wrapper lib (like helix/reagent/etc.) can generate these signatures using a macro, but requires integration at the reload step to properly invalidate them like I was saying
yeah, I dunno I'd have to look more closely at how it works to have any clearer thoughts
@lilactown but one question I have is how is react-refresh really any better than just developing a RN Reagent app over a state atom w/ Figwheel / shadow / soonish Krell?
In a web app this often not that fun - but for shallow view graphs in mobile I don't see the problem
if you take the stance that local state and global state are functionally and architecturally identical, I agree with you.
that's all I'm interested in though - if the end result is same performance, same experience
I haven't followed along but you also have Om inspired projects - the reconciler does what you're talking about
Om's idea is that you have global state - but the reconciler gives you precise updates
especially with concurrent mode unlocking more perf and experience knobs for devs, which works best with local component state
like I said I don't have a strong opinion and I personally think there are alternatives
reading over https://reactnative.dev/docs/fast-refresh it doesn't seem very simple and lots of caveats - so meh
Haven’t dove down to fast-refresh for React Dev yet, but I can comment on the state bit - my goal is to take advantage of the new React Concurrent mode when it lands. So far, and until some new docs land, React wants to you let it handle state (there was months of churn to figure out how this could work with global state).
This also impacts you more the more you rely on hooks, and the more you rely on JS components that use hooks. Fast-refresh promises to keep state from hooks and rerender, for free. Seeing that esp. for UI work local state makes some sense, preserving that makes sense.
@orestis yeah I haven't followed the Concurrent mode stuff that closely - it does look interesting - but I don't know what you mean by "React wants you to let it handle state"
what he means is that, Concurrent mode works best when your state is coupled to an instance of a component.
construction/destruction relies on mount/unmount, updates to state mean the component re-renders, etc.
concurrent mode allows React to pause rendering a tree and resume rendering that same tree later. this creates problems if the state that was rendered in multiple parts of the tree has changed in between pausing and resuming
React can handle this in a transactional fashion if you manage state inside the component instance. it essentially puts state updates on a queue that gets computed on the render that it triggers. if you store state outside of a component instance, then React can’t handle those state updates for you - if you update an external state atom in a naive synchronous way then you can end up with parts of your tree that were rendered using an old atom state, and parts that were rendered using a newer atom state. if you store state once, and it lives in a component, then resuming the tree will either re-use the state updates already computed inside that render, or compute those state updates against the latest state. you avoid the sort of coherency problems that state external to the tree can introduce.
react is adding more tools to handle external state but the happy path is definitely storing it inside a component using
The most annoying thing is that this is very much in flux. This approach for examples invalidates all the major React global state managers (redux, relay, Apollo). There’s an RFC called useMutableSource IIRC that seems to handle this, and to my knowledge @mhuebert did a POC some time ago for ClojureScript. I’ve kind of decided that I’ll wait until an official release or more guidance is available.
My only fear is that as with fast-refresh, the React devs will end up with just a Babel/webpack plug-in that we will have a hard time incorporating into our dev workflow.
If I had time to focus on this I’d definitely try to reach out to the React team, they said they wanted to release concurrent mode under an experimental release so that tooling can catch up. Sadly my day job leaves zero time for this kind of low level stuff.
But to be fair to them, they are trying the best and using the new Facebook as a guinea pig.
The plan AFAICT is that the official release will be simultaneous with major libraries so the change for consumers will be mostly under the hood.
well this still seems a bit far out to me and upgrading legacy applications seems like a monumental task
yep 😛 all of this CM talk is just motivation for why I desire good react-refresh integration
I expect that libs and apps that use non-CM safe patterns will continue to be supported for a long time. there are a lot of different “modes” that allow devs to tune React to what works with their code
Actually the new bundle stuff sounds like we can finally start releasing tools that depend on React and other npm stuff more easily.
I totally wish React had put Concurrent into a new lib with different name. I am just glad that this useMutableSource stuff is finally arriving. Looks to me like it is going to work well.
@dnolen was there a tools/repls page that got removed on the cljs site?
yeah, guess so - that was the top nav link for tools, so this broke a bunch of nav
I'm talking about the top level nav - the Tools link went to that page
ah k, I didn't understand nav worked that way - it shouldn't have been the top link at this point
I can easily add redirects from old links to somewhere new too if you run into that, there's a list of those in the deployment
should be fixed up now - there's now a tools/tools page which is in the clojurescript-site that mostly matches the left nav
@dnolen not sure if you are monitoring ClojureVerse, some comment left there on Node versions: https://clojureverse.org/t/test-drive-the-beta-clojurescript-js-bundler-integration-support/5779
Related to JS modules, I've been already thinking about adding notice to Cljsjs page and repository strongly suggesting using other ways to consume JS libraries. Now is even better time for that.
I close this one old module processing issue, couldn't reproduce the problem now: https://clojure.atlassian.net/projects/CLJS/issues/CLJS-2836
I think https://clojure.atlassian.net/browse/CLJS-1543 this is now done (goog.module support)?