This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-09-04
Channels
- # aleph (1)
- # announcements (7)
- # beginners (22)
- # calva (31)
- # cider (2)
- # clj-commons (1)
- # clj-http (2)
- # clj-kondo (10)
- # cljsrn (33)
- # clojure (18)
- # clojure-europe (7)
- # clojure-nl (3)
- # clojure-uk (2)
- # clojurescript (93)
- # depstar (3)
- # events (1)
- # figwheel-main (3)
- # fulcro (13)
- # graalvm (95)
- # graphql (1)
- # introduce-yourself (1)
- # lsp (92)
- # off-topic (2)
- # pathom (11)
- # releases (1)
- # shadow-cljs (33)
- # specter (6)
- # tools-deps (4)
- # vim (3)
- # web-security (1)
- # xtdb (7)
Sup y'all, I'm hacking on this auto-transducifying thread macro and I'm trying to figure out how best to integrate it with Clojurescript: https://github.com/johnmn3/injest
I could store the things as quoted symbols but that works more anaphorically, so if you register 'x/reduce
then all your namespaces have to use the same aliasing for the macro to see it, which kinda sucks. I'd prefer to namespace qualify the symbols in a given thread and test those against the namespace qualified versions stored at initialization, but I can't get it to work across both clj and cljs
Could probably drop into the analyzer to get it done, but I'd think the clj macro would be able to resolve the symbol at compile time
Also, I'm curious if when another person clicks on the codespaces link, if they get a vscode with calva that they can launch repls with. I think I have a basic one working
@lilactown @dnolen Correct, stories and component in CLJS. They are compiled to JS, along with all dependencies. Then the folder containing all that compiled JS is processed by webpack somehow, node_modules too. I tested now with just this repo https://github.com/DavidVujic/clojurescript-amplified, commented out the amplify stuff. Findings in thread to not spam main thread here
Running that repo with no changes (except commenting out some amplify stuff that didn’t work), storybook is loaded in browser within 10-15 secs.
Then, if I add a dependency on specter and require it in the core NS, this is what happens after about 60 secs of run time.
Storybook uses Webpack under the hood. In my example repo, I have used the very latest version supporting Webpack 5 with additional Webpack specific config, to make it work along the other things I’ve added in the repo (AWS Amplify and Material-UI).
In short, this is how I think the ClojureScript and Storybook integration works:
writing code in ->
shadow-cljs will compile it to JavaScript and put it in a public folder ->
the running storybook process will pick up the changes and do some JavaScript packaging magic under the hood (involving Node.js and Webpack) 😄
Sorry if I have missed any info about the issues in the discussion. I was thinking it might have something to do with the Node.js version running?
Alternatively, I’m thinking that it might be that Storybook doesn’t fully support Weback 5 yet. https://storybook.js.org/blog/storybook-for-webpack-5/
I’m not familiar with the specter.js library, do you have any code that can be shared? I would like to help out finding what’s causing this.
I’m just randomly selecting that particular library because it’s rather big and predictably breaks storybook build. Added dependency
[com.rpl/specter "1.1.3"]
And require
[com.rpl.specter]
Seems like lots of 100k+ files in the same folder as the stories js files isn’t a common usage pattern for normal storybook users
Good find! Maybe it could be solved by setting the storybook alias in “production” mode (I’m not sure how, though)? I’ll try that out with my setup.
I’ve seen a lot of talk about excluding folders or file pattern from babel/webpack processing. Not been able to configure anything that makes a difference, though
I’m not sure if this is an approach that is good or bad. Currently experimenting … and not fully automated yet. When changing the folder Storybook is looking for files to:
"stories": [
"../public/js/stories/release/*_stories.js"
],
(.storybook/main.js)
And triggering a 
shadow-cljs release stories --config-merge '{:output-dir \"public/js/stories/release\"}'
With both re-frame and specter included, Storybook seems to manage building fine. Before that, I experienced the same issues as you.
The release build should be automated somehow, to have a nice dev experience. Something should be watching the dev output and trigger the shadow release process.
I’ll continue trying out this, and will update the example repo if this is realistic in practice.
Interesting! To me it sounds likely that the release build works because it’s only one file, and much less processing need for webpack?
feel free to open an issue about this. ideally without a reproducible repo. I can see if I can figure something out to hide the CLJS output since it really doesn't need to go through webpack
@U05224H0W great! But wouldn’t it be easier if we could configure webpack to skip all files in that folder?
I don’t know it it would be possible (or make sense 😄 ) - if a dev build could be tweaked with compile-options to output something similar to release builds? Then it would be possible to watch changes in an alias.
it has to process the files. kind of at least. needs to be able to find the stories after all
Correct me if I’m wrong, but seems to me storybook uses babel for transpiling things like typescript and JSX in stories. None of this is needed for compiled CLJS, right?
I think you might have solved it @U21QNFC5C 😄 I have replaced all the storybook webpack rules and it seems to build very very fast. Probably, there are some of the existing rules that should be there, but this is probably the way to solve this issue. Great!
Here’s the rules replaced (i just console-logged the config):
[
{
test: /\.(mjs|tsx?|jsx?)$/,
use: [ [Object] ],
include: [ '/Users/david/github/clojurescript-amplified' ],
exclude: /node_modules/
},
{ test: /\.js$/, use: [ [Object] ], include: [Function: include] },
{ test: /\.md$/, type: 'asset/source' },
{
test: /\.js$/,
include: /node_modules\/acorn-jsx/,
use: [ [Object] ]
},
{ test: /(stories|story)\.mdx$/, use: [ [Object], [Object] ] },
{
test: /\.mdx$/,
exclude: /(stories|story)\.mdx$/,
use: [ [Object], [Object] ]
},
{
test: /\.(stories|story)\.[tj]sx?$/,
loader: '/Users/david/github/clojurescript-amplified/node_modules/@storybook/source-loader/dist/cjs/index.js',
options: { injectStoryParameters: true, inspectLocalDependencies: true },
enforce: 'pre'
},
{
test: /\.css$/,
sideEffects: true,
use: [
'/Users/david/github/clojurescript-amplified/node_modules/style-loader/dist/cjs.js',
[Object]
]
},
{
test: /\.(svg|ico|jpg|jpeg|png|apng|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/,
type: 'asset/resource',
generator: { filename: 'static/media/[path][name].[ext]' }
},
{
test: /\.(mp4|webm|wav|mp3|m4a|aac|oga)(\?.*)?$/,
type: 'asset',
parser: { dataUrlCondition: [Object] },
generator: { filename: 'static/media/[path][name].[ext]' }
}
]
in .storybook/main.js I have set the rules like this:
config.module.rules = appConfig.module.rules;
and that seems to have worked 😄 Will continue with this tomorrow.
one thing it might have been doing is combining the source maps. that usually is a bit expensive.
I think I tried with :compiler-options {:source-map false} in the stories alias (in my example storybook repo) but there still were map files generated. Is there another way to tell the compiler to not add map files?
development always adds them, you really really want them anyways. otherwise any errors are going to be a nightmare to debug
Makes sense!
It’s a mystery to me why this fix works. Been looking through those rules, and only 2 of them match JS files, none match MAP files. And the 2 JS matchers are directed at very specific modules inside node_modules
But maybe some JSX rule processes the storybook JSX files, and from there drills down into stories specifics
I have pushed a solution I think will work. With less Storybook/Webpack hacks. Try it out (I also bumped the storybook and webpack libs to the latest version). This will also make the Storybook watch & build way faster. The update: https://github.com/DavidVujic/clojurescript-amplified/commit/cf5bd1700581f62abbc760000d0cb3d15ec24ca3
ah so its babel causing the issues again. makes sense to disable, not needed at all anyways
tested now, works! Thank you @U018VMC8T0W. I’ve been searching for that particular config change 🙂

Here is documentation on how this
works (`this-as` just makes this
accessible in given "block": https://cljs.github.io/api/cljs.core/this-as) https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this (not really an example but it might make things more clear.... maybe.)
maybe this would be ok example then? (tested using http://clojurescript.net/):
(defn test
"Increments counter and returns current value."
[]
(this-as this
(set! (.-counter this) (inc (or (.-counter this) 0)))
(.-counter this)))
(test) ;; => 1
(test) ;; => 2
(defn test2 [])
(def test3 (.bind test test2))
(test3) ;; => 1
(test) ;; => 3
@U662GKS3F what is this
in the test
function?
> what is `this` in the `test` function? that's easy to test:
(defn return-this []
(this-as this
this))
(return-this) ;; => #object[Window [object Window]]
meaning this
equals to js/window
.right, so I was looking for an example where this-as this
doesn't refer to the global object in CLJS
I tried making something with #js {:a (fn [] (this-as this)}
but it didn't work for me
it is highly dependent on how you call it. can you show an example of how you tried to execute the a
method?
> right, so I was looking for an example where `this-as this` doesn't refer to the global object in CLJS
I don't really use this
much in js, but in the example - test3
has this
bound to test2
function. In js, functions work kind of like objects (yeah - it's messy)
The reason I'm asking all of this is that I would like SCI to have more compatibility with CLJS and I'm looking for test cases
this
depends on where you call the function from and bind
can fix the this
value so that it is not dependent on caller (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind)
@U04V15CAJ without seeing the full example I can't tell you what was wrong with how you were testing it, but this worked for me:
cljs.user> (def o #js {:a (fn [] (this-as this this))})
#'cljs.user/o
cljs.user> (.a o)
#js {:a #object[a]}
it is also very flexible, i.e. you can create methods outside the context of the object and then attach them after the fact
cljs.user> (defn a [] (this-as this this))
#'cljs.user/a
cljs.user> (def o #js {:a a :name "o"})
#'cljs.user/o
cljs.user> (def o2 #js {:a a :name "o2"})
#'cljs.user/o2
cljs.user> (.a o)
#js {:a #object[cljs$user$a], :name "o"}
cljs.user> (.a o2)
#js {:a #object[cljs$user$a], :name "o2"}
there are ways to statically bind what this
refers to in a function, like what @U662GKS3F linked above
in modern JS, it's now popular to use the arrow syntax () => {}
for constructing functions which statically binds this
in the way one would expect coming from other languages, i.e. this
stays the same after construction no matter what object it is "attached" to
I'm trying to figure out if there is a way to get to "this" in SCI. Because it's not a compiler, it seems... difficult. E.g. this returns true:
cljs.user=> (sci/eval-string "(def o (clj->js {:a (fn [] (identical? js/goog.global (js/eval \"this\")))})) (.a o) " {:classes {'js goog/global :allow :all}})
true
while it should not.It does seem like the js/eval
approach works in CLJS:
cljs.user=> (def o (clj->js {:a (fn [] (js/eval "this"))})) (.a o)
#'cljs.user/o
#js {:a #object[Function]}
so I do think it should be possible to make it work in SCI as wellto get a new non global this
you need new
(defn my-constructor []
(this-as this
(set! this -foo "bar")))
(let [obj (my-constructor.)]
(js/console.log obj))
you can also set it for any function via .call
or .bind
but typically this
is just the current object assumed to be constructed via new
(or the thing.
sugar for that)
Got a temporary work around in place for ClojureScript - gotta register symbols in a clojure (`.clj`) namespace. Transducer authors could probably ship with injest
registrations that work in clj and cljs seemlessly for their users though. If anybody notices a better workaround that allows registration from cljs, let me know
I have pushed a solution I think will work. With less Storybook/Webpack hacks. Try it out (I also bumped the storybook and webpack libs to the latest version). This will also make the Storybook watch & build way faster. The update: https://github.com/DavidVujic/clojurescript-amplified/commit/cf5bd1700581f62abbc760000d0cb3d15ec24ca3