This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-07-04
Channels
- # beginners (8)
- # boot (20)
- # cider (8)
- # cljs-dev (263)
- # cljsjs (8)
- # cljsrn (20)
- # clojure (151)
- # clojure-argentina (1)
- # clojure-belgium (7)
- # clojure-dev (18)
- # clojure-italy (25)
- # clojure-spec (34)
- # clojure-uk (15)
- # clojurescript (89)
- # component (45)
- # core-async (27)
- # cursive (16)
- # datomic (53)
- # emacs (40)
- # figwheel (3)
- # hoplon (62)
- # jobs (1)
- # jobs-discuss (7)
- # luminus (8)
- # lumo (60)
- # off-topic (3)
- # parinfer (1)
- # precept (1)
- # protorepl (15)
- # re-frame (37)
- # reagent (7)
- # ring (3)
- # ring-swagger (73)
- # slack-help (1)
- # specter (19)
- # sql (4)
- # test-check (10)
- # uncomplicate (2)
- # unrepl (14)
- # untangled (52)
- # vim (5)
- # yada (42)
@dnolen I'm not sure what the proper protocol is, but I wanted to follow up and let you know that I submitted that bug+patch: https://dev.clojure.org/jira/browse/CLJS-2162
Also, there are a number of issues outstanding on the browser repl. I realize that's not exactly a hotspot of activity with figwheel out there, but I probably have enough knowledge to tackle any of them. I'm curious if you'd be interested in having some particular ones resolved, or if it would just be a distraction.
@dnolen wanted to get your thoughts on the new goog.module
stuff where goog.require
returns a value now
what’s the value proposition there? is it maybe at odds with Clojure(Script) namespaces?
@dnolen I was experimenting with modules and had a case where loader/load
is called before loader/set-loaded!
. Not sure why, but a callback to load
is never called. Even though requested module was loaded with all its dependencies.
@dnolen Doing so seems wrong to me anyway, but I believe this should be clarified somewhere to avoid more confusion. Maybe compiler warning would help here
@dnolen In my case this was not obvious because I have a call to load
in Reagent component which is being rendered right after component declaration. Later I figured out that that load
was called before set-loaded!
because the first render is always synchronous in React.
@roman01la you need to make something minimal that demonstrates the problem, as it is I don’t really understand what you are saying
I’m confused because you haven’t even mentioned what modules were involved (A, B or whatever)
ok, I’ll drop a link later today
@anmonteiro I guess that’s attractive for some reason for Closure devs? I’ve seen it before and I’ve more or less ignored it since I don’t see them changing the standard lib to that format anytime soon. Unless of course you’ve heard otherwise?
@potetm first glance patch looks ok, thanks! If you want tackle some outstanding issues with browser REPL / server go for it!
@petterik well looks like no need for YourKit, just needed a memoize, instead of 400s it now takes 400ms
@dnolen Nice! Perf issue is fixed:
Successfully compiled "/Users/petterik/Github/......./main.js" in 145.941 seconds.
Not getting React is not being added to cljs_base.js for me. Have you seen this problem?
@petterik thanks again for your modules/sources from yesterday, looks like a very non-trivial project 😉
You're welcome! Couldn't have built this project without cljs and om.next 🙂 Launching this month!
@dnolen Have you started with js-transforms load code already? Or should I take a look at implementing that?
@juhoteperi if you want to do that be my guest 🙂 was just thinking about that
I'll have a look at it. Should be quite simple.
Did you have idea about validating the keys: "We should only support namespaces transform keys". As the files are just eval'd and just contain defmethod there is nothing to validate during loading these files?
My understanding is that the files would look like this: https://github.com/cljsjs/packages/blob/cljs-2143/babel-standalone/src/js_transform.clj
@juhoteperi yeah … it seems ok
https://clojurians.slack.com/archives/C07UQ678E/p1499171331003454 Going to put a zip here.
@juhoteperi given that you need to get at a JS engine and who knows what I else I don’t think trying to be declarative is productive
@dnolen That is what I thought also
@juhoteperi OK! yeah, don’t worry about namespaced keys - if people mess it up it will be obvious
Default method already provides a warning about missing preprocess handler
@roman01la what am I supposed to do, what am I looking at, how do I reproduce, etc. etc.
Sure. So if compile the project and open it in the browser you’ll probably see a message in the console, once a module is loaded via loader/load
.
The problem is that loader/load
is called before injected loader/set-loaded!
, so you’ll see that modules are fetched twice (via script tag and xhr)
ok, so the module :app
has this code (loader/load :page callback)
, that is called before (loader/set-loaded! :app)
, which is injected by compiler
both :app
and :page
depend on :common
which depends on :cljs_base
because :app
calls (loader/load :page callback)
before (loader/set-loaded! :app)
it causes ModuleManager
to load not only :page
but also :common
and :cljs_base
so the first thing is that modules are fetched twice: first via script tag and then by ModuleManager
if so why would you do this? you might as well have an explicit dependency in that case
(defn load-js-transforms! []
(doseq [url (get-js-transforms*)]
(with-open [rdr (io/reader url)]
(binding [*ns* (create-ns (symbol (random-string 5)))]
(load-string "(clojure.core/refer 'clojure.core)")
(load-reader rdr)))))
Okay, getting the list of files is easy. But what is the best way to load them? They can't use ns
as they won't be in correct path relative to classpath, but when loading the code, a namespace should be used so cljs.closure
is not contaminated with requires/vars from loaded files. This code works, but using random-string
for namespace names is bad idea as it will create new namespace each time this function is called.@juhoteperi should just copy Clojure’s loading of data literal files
Hmm, right didn't check there, just looked at Cljs data literal file reading
@dnolen In the app I had a Router
component which loads modules depending on which route is active now. When the app loads initially the very first render in synchronous. Because (loader/set-loaded! :app)
is injected into the end of the file and component is rendered synchronously, module load is fired before (loader/set-loaded! :app)
. I think this is a common scenario to load components in route-based code splitting
@roman01la we’re going to need better reason than random routing stuff
Draft of copy introducing the new aget
, aset
warnings for consideration for the official blog. It may be short enough for embedding in a larger post, and it is also long enough to potentially stand on its own: https://gist.github.com/mfikes/ba5e999eeef8295ee9d8d53af94ebc18
@roman01la all the Closure docs for ModuleManager show setLoaded coming at the end of namespace far as I know, top level loads before hitting the end of the file seems like a no-no
@roman01la you can also call set-loaded!
yourself
load-data-readers
doesn't help with this as data_readers files will only read a single object form the file and that must be a map.
@juhoteperi ah right because it assumes you already loaded the required fns explicitly
@juhoteperi clojure.core/load
?
@dnolen Sure I did exactly this. That's why I think a warning could be useful or at least there should be more info on that. ModuleManager is hidden behind cljs wrapper and it's not obvious how it behaves in such cases.
The example I pasted already uses load-reader
which is easier to use with URLs from getResources and this works
But load-reader
(and I think load
) will evaluate the code in current namespace?
Should be very confusing for someone coming from Webpack for example.
@roman01la but a warning for what, and how would we detect such a thing?
@dnolen Could be a runtime warning in development. ModuleManager keeps track of loaded dependencies, we can notify about load
call if current module is not loaded yet
@juhoteperi ah right - hrm I dunno might need just play around wit this
@roman01la there is no such thing as “current module”
at least not without a whole bunch of injection stuff that I’m not interested in at all
@roman01la … we could make load
a macro I guess
@dnolen It's working! Last problem was just sloppiness integrating the cljs.loader ns.
I'm using cljs.loader/loaded?
in my Router's shouldComponentUpdate
. Not rendering if it's not loaded yet
My first render happens after the callback to cljs.loader/load
with my initial route
@roman01la Wouldn't your problem be solved by just dropping the load
call into a microtask?
@roman01la we could make load
validate if it’s called statically (i.e. macro + runtime fn)
@dnolen I signed this one yesterday before creating the patch Clojure CA between Rich Hickey and Petter Eriksson is Signed and Filed!
@rauh it would, there are multiple solutions if you know where is the problem :)
@dnolen Here is one solution using classpath relative path of file munged as namespace name: https://github.com/Deraen/clojurescript/commit/bb94e566a8827d0356740491e2506fba02faa109
Oh except all the js_transform files from jars will have same classpath relative path...
@juhoteperi something like that seems like the right direction
It will probably work without relative-name
, the namespace names might be very long but I hope that won't cause problems
@dnolen not sure how that would look like, but I'm up to any improvement :)
@roman01la nothing would change
@juhoteperi what about js_transform_GENSYM
?
@dnolen The name should be stable between load-js-transforms!
calls so that it won't create new namespaces each time build
is called. But could work if the names were generated in the memoized fn.
Or there could be a atom for URL -> symbol mapping
@dnolen Hehe. This might doesn't seem like a big deal, but devs would appreciate this, especially when it's a new thing in cljs, imo
Or the URL -> symbol mapping could be stored in compiler state
@roman01la will think about it
@juhoteperi why not just SHA the URL?
Ha, that would also work. The result will be shorter than mungle-path.
loading file:/home/juho/Source/clojurescript/src/test/clojure/js_transform.clj js_transform_7596B998B31634FDE39058D5B7FA3055C958148C
loading jar:file:/home/juho/.m2/repository/cljsjs/babel-standalone/6.18.1-3-SNAPSHOT/babel-standalone-6.18.1-3-SNAPSHOT.jar!/js_transform.clj js_transform_9CA4F1F139C72C4EC1A9BA1AF2DB184C7FA20DFE
Seems okay@dnolen thanks!
for the record I think js_transform.clj
is a bad idea. IMHO we should just allow :preprocess some.qualified/symbol
(maybe even as a vector). the compiler can then load the namespace via require
and find-var
expecting to get an fn
.
@thheller Yes, I think that might be cleaner solution
With this approach, the file is loaded (evaluated) each time cljs.closure/build
is called, require would automatically only eval the first time
I'll create another branch with that version
Another benefit is that if the loading is done when preprocess value is found, it will be lazy and only those namespaces that are really needed are loaded.
Initializing JS env in Babel-standalone file probably takes some time so running that everytime cljsjs/babel-standalone is present in classpath might be bad idea
(Except cljsjs code uses delay so it will be only created when calling js-transform first time)
@juhoteperi if we’re going to support :preprocess
as symbol then we don’t need to be tied to js-transform multimethod
and we can also think about threading a new argument for sharing information between transforms
I noticed this morning that :file is an absolute path in cljs, but is classpath relative in clojure. I couldn't find any reference to this being different anywhere. Is this a bug? I did notice a blog post from 2xx that hinted that :file was relative, but it wasn't by 3xx.
@dnolen for tooling. For example in boot the file is in a temporary path, but you actually want to open the real path.
@dominicm This is tooling issue
@juhoteperi if absolute paths are necessary then yep. I wasn't sure they were. I can move this to #boot I guess now. But is there anything that can be done to control the resulting metadata. I've made a PR to cider which attempts to convert an absolute path to a classpath uri, but it's not great. Come to think of it, it probably belongs in cljs-tooling
@juhoteperi before just hacking this out we might want to just write up what this will look like for end users
maybe we don’t need extra arg - but it does seem useful to share engine/babel in some cases?
Another useful feature is for the implementations to be able to read options from the ijs
map, like the babel example:
:foreign-libs [{:file "src"
:module-type :es6
:preprocess :cljsjs.babel-standalone/babel
:cljsjs.babel-standalone/babel-opts {:presets ["react" "es2016"]}}]
Which is already possible
@juhoteperi if absolute paths are necessary then yep. I wasn't sure they were. I can move this to #boot I guess now. But is there anything that can be done to control the resulting metadata. I've made a PR to cider which attempts to convert an absolute path to a classpath uri, but it's not great. Come to think of it, it probably belongs in cljs-tooling
Perhaps the docstring I added to unsafe-get
said too much (given that it could be used on arrays)
"Efficient alternative to goog.object/get which lacks opt_val and emits
unchecked property access.
“INTERNAL. Compiles to JS property access using bracket notation. Does not distinguish between object and array types and not subject to compiler static analysis.”
Js-transforms options: https://gist.github.com/Deraen/9cf7d04221450bc10ac571399a483c4d
@juhoteperi FWIW, if you're still thinking about using the SHA we probably just need the first 7 chars like we do here: https://github.com/clojure/clojurescript/blob/master/src/main/clojure/cljs/analyzer.cljc#L3501
@dnolen I don't have a compelling reason to use goog.module
, just something I was reading about yesterday.
A big advantage to me is that it would probably enable CLJS to output commonJS if we ever wabted
Since the formats don't look very different to me
Provided the core Closure lib moves to it I suppose
Btw FWIW we've been using :fn-invoke-direct
since 1.9.671 without any problems /cc @rauh
We like this feature a lot so so much.
@anmonteiro generating CommonJS is interesting, but to me the problem is still that who would want to consume it? - we generate a lot of code and most JS bundling tools just aren’t designed to handle it well
I can see a future where generating CommonJS modules just integrates better with the entire ecosystem
e.g. embedding a CLJS app in a JS one
I’m sure e.g. Webpack could handle our code if we generated CommonJS
@anmonteiro yeah that’s an interesting reason - just need more investigation about what the repercussions would be
@anmonteiro Wouldn't generating ES6 modules instead of CJS be more future proof? Would work in browsers directly,.
I don’t even know if it’s feasible today
just that the goog.module
thing really resembles commonJS
maybe a summer of code project for 2018 🙂
yeah ES6 would be even better
and really suits Closure in that dependencies need to be known ahead of time
@dnolen @anmonteiro in case you guys didnt see. https://gist.github.com/thheller/74473e8b9ca2b795962d0f65fdecf8af
even for the web there’s value
if your goal is to use Webpack to package a bundle
you can just emit commonJS modules and have Webpack take care of the rest
granted, it’s introducing one extra tool…
maybe people are clamoring for better Webpack integration but to be honest I’m not hearing it that much
@thheller TBH I’ve been meaning to look at shadow but still haven’t had a chance
what’s the fastest way I can get acquainted with it? 🙂
my argument was that it should be easier to use CLJS in a project that already has lots of JS with tools for it
^ but this is only a fraction of the people
we shouldn’t necessarily optimize for the 1% IMHO
dnolen: please take us into consideration, I'm self-taught to work on front-end, nearly zero experience in JVM. I know several people similar to me in China learning ClojureScript without really using Clojure. Meanwhile Webpack is already our everyday life.
I'm fine with all my code in cljs when toolchains covered all my work. However sometimes I ran into situations that are not covered, first time I think is Webpack has done that, if I can get CommonJS result, I can do that with Webpack.
my commonJS / ES6 module suggestion was more of a long term goal / north star to have in mind
@anmonteiro probably by checking out one of the shadow-cljs-examples
and running it? 🙂
maybe we can move this somewhere else, but I have trouble with declarative stuff. is there a programmable API?
@anmonteiro the docs for the low-level stuff are non-existent but this namespace is sort of the official API https://github.com/thheller/shadow-cljs/blob/master/src/main/shadow/cljs/devtools/api.clj
gotcha, I’ll have a look later
thanks for indulging 🙂
@dnolen just got this working locally:
(ns foo.core
(:require ["react" :refer [createElement]]
["react-dom/server" :refer [renderToString]]))
(enable-console-print!)
(println (renderToString (createElement "div" nil "Hello World!")))
what’s better for you to review? attached patch to JIRA or GitHub diff?
@anmonteiro whoa, JIRA patch is fine
let me clean it up
@dnolen @thheller Did you check my notes about js-transforms? Opinions on multimethod + keywords vs symbol + function? https://gist.github.com/Deraen/9cf7d04221450bc10ac571399a483c4d
@juhoteperi I have to run will be take look later today or tomorrow
Great. I myself prefer symbols+functions a bit over keywords+multimethod. Should be a more obvious to users that when they see the symbol in foreign-libs map, it refers to a function.
patch attached to https://dev.clojure.org/jira/browse/CLJS-2061
example included in the samples/
folder
surprisingly small patch too
@anmonteiro Did you try case where CJS module only exports single function? Like create-react-class
did not
in that case you need to alias
or rather, if the module is of the form "react-dom/server"
, you need to alias
let me try that real quick and amend the patch if it doesn’t work
Works currently so probably it will work with the patch
This patch only support JS Modules with this string require?
what do you mean?
It preserves backwards compatibility if that’s what you’re asking
Doesn't work with non-js-module foreign libs
you can still (:require [react])
I think it might
but I didn’t try
actually it might not work, but could be changed to work
but my reasoning is: if you have a foreign lib with an explicit :provides
, you can just require it with symbol
Would be very valuable if libraries can use same require forms for CommonJS and browser-ready-JS-files
e.g. reagent would use (:require ["react"])
and this would work both with cljsjs/react and :npm-deps {"react" ...}
(if this was implemented, cljsjs/react would provide the same "namespaces" as commonjs modules)
Problem is that there is no clean mapping between the name (`react`, react-dom
, react-dom/server
) and the object the foreign lib file provides (`React`, ReactDOM
, ReactDOMServer
).
@juhoteperi wrote a comment on the :preprocess
gist
:foreign-libs
could provide that mapping easily, just would need to do the same trick I do in shadow.cljs
. ship a .js
file that goog.provide("some.alias"); some.alias = React;
@juhoteperi updated the patch with an example for the single export case
basically this just works:
(ns foo.core
(:require "create-react-class"))
(println create-react-class)
@anmonteiro don’t do that, that should never be allowed
now if you have stuff like "react-dom/server"
you’ll need to alias
we already do that
just not for string requires (because we don’t support them yet 🙂 )
this is not a global name
it’s just a way we resolve variables inside the namespace