This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-07-28
Channels
- # aleph (1)
- # arachne (4)
- # beginners (13)
- # boot (18)
- # clara (7)
- # cljs-dev (156)
- # cljsrn (278)
- # clojure (163)
- # clojure-conj (5)
- # clojure-dev (1)
- # clojure-losangeles (1)
- # clojure-poland (2)
- # clojure-sg (1)
- # clojure-spec (15)
- # clojure-uk (17)
- # clojurescript (275)
- # data-science (5)
- # datomic (23)
- # emacs (10)
- # leiningen (1)
- # lumo (16)
- # off-topic (98)
- # onyx (10)
- # parinfer (83)
- # re-frame (18)
- # reagent (47)
- # remote-jobs (1)
- # ring (1)
- # ring-swagger (5)
- # rum (6)
- # specter (8)
- # vim (5)
@jeremys figured out your problem
this is ES6
but we assume every NPM dep is commonJS
so we’re not converting it and can’t extract the correct provides
does the compiler provide a way to prevent the renaming of particular namespaces? if I wanted to expose my-ns.core
to the outside world even under :advanced compilation, how would I do that? an externs file doesn’t seem to affect the output namespaces (wouldn’t expect it to, I dont think)
(defn ^:export x ...)
so that will preserve “my-namespace.x” such that I can call window.my_namespace.x
instead of just preserving x but clobbering my-namespace into something like window.ab.x = ...
?
Does this https://clojurescript.org/news/2017-07-12-clojurescript-is-not-an-island-integrating-node-modules work with :advanced optimizations out of the box?
@jeaye doesn’t obviate the need for externs if that’s what you’re asking
the advantage of having CLJSJS though
it that you can have those in the classpath without actually requiring the namespaces
and CLJS will crawl the classpath for externs
I think @mfikes was working on RN externs
right
probably easy enough to generate externs with https://jmmk.github.io/javascript-externs-generator/
Does that site work for you, @anmonteiro?
what problem are you having?
I'm putting in this URL: https://github.com/auth0/react-native-lock/blob/master/auth0-lock.js
probably doesn’t work with ES6? let me try
@jeaye raw github link also gives me this error in the console:
Refused to execute script from '' because its MIME type ('text/plain') is not executable, and strict MIME type checking is enabled.
it probably wants bundles as well
won’t be able to eval const Auth0 = require('react-native-auth0');
if you only pass it that file
which may be hard for React Native stuff
So, using RN and I've installed a dozen RN packages through NPM. What would be the best way of getting externs for them?
@anmonteiro So, assuming I can generate some externs, then, using your latest changes, I should not use js/require
, but instead :require
to bring them in (directly from node_modules
), add the externs to :foreign-libs
, and I should be all set?
using module/function
instead of (.function module)
Furthermore, does that new change allowing :require
obviate the need for one to specify the {:file "foo.js" :provides "foo"}
in :foreign-libs
?
or rather
yes, if foo
is in node_modules
So, with js/require
, even if foo
is in node_modules
, I'll need to use {:file ...}
in :foreign-libs
as well as put the relevant data in :externs
. With :require
, I need only do the externs.
with js/require
you don’t need foreign libs entries
under :target :nodejs
(or any other environment that has native require
) it’ll just emit require
calls that are resolved at bundling-/runtime
I'm targeting react native, but I do have js/require
(and I am currently using it everywhere).
right, because the react native packager will parse your source files for require
and resolve them at bundling time
but you don’t need foreign libs for those things
in fact, they won’t be used at all, because the packager is going to resolve js/require
s in node_modules
Ok, so, for my situation, even with js/require
, I'll only need externs for each of the libs.
@anmonteiro To be super clear, does this also mean I don't need to worry about the :requires
bit of :foreign-libs
, as that is all figured out through the packager?
that’s right
I ask all of this because the cljs website doesn't detail this at all and only documents the situation where all of this is needed.
you don’t need foreign libs at all
you just need a deps.cljs
at the root of your classpath with an :externs
entry
;; deps.cljs
{:externs ["/path/to/externs.js"]}
just put more paths in that vector
Hi, I am trying to require npm dependencies in a cljs project, my dependencies are like
[org.clojure/clojure "1.9.0-alpha17"]
[org.clojure/clojurescript "1.9.671"]
the build like
:cljsbuild
{:builds
[{:id "dev"
:source-paths ["src/cljs"]
:figwheel {:on-jsload "myproject.core/mount-root"}
:compiler {:main myproject.core
:npm-deps {:mapbox.js "3.1.1"}
and in my namespace
(ns myproject.views
(:require [re-frame.core :as re-frame]
["mapbox.js" :as mapbox]))
but when running lein cljsbuild once dev
it raises an exception clojure.lang.ExceptionInfo: Library name must be specified as a symbol in :require / :require-macros; offending spec: ["mapbox.js" :as mapbox] at line 1
Which I believe shouldn't happen with this version of clojurescript?@jazzytomato the feature is still alpha and often requires a lot of manual tuning
I only looked briefly over the source but there are many things in there that are probably not supported
for ["mapview.js" :as mapview]
to work you might also need to specify mapview.js
in :npm-deps
sorry I meant ["mapbox.js" :as mapbox]
in my namespace, updated my message
@jazzytomato you need to use master
aaahhhhh ok! from the blog post "ClojureScript is not an Island" I thought this was released. Thanks!!
no @jazzytomato, those are sneak preview posts
no worries, that's awesome anyway
@anmonteiro I have tried with
:language-in :ecmascript6 :language-out :ecmascript3
but it doesn’t change the outcome. Thanks for taking the time I will follow along on the jira.I’m writing a ClojureScript app w/Reagent/Re-frame and I’m wondering how to properly handle logout when the user’s token expires. I’m assuming I should do something like have an AJAX interceptor that checks for 401s and then dispatches a “logout” event?
@taylor best to ask on #re-frame channel
Hi! Is there a relatively simple way to generate an NPM package for a CLJS project, where the CLJS project namespaces are built into individual JS modules?
I can think of at least one hacky way: Use shadow-cljs to build the individual JS modules, then copy them somewhere for package.json to find them.
I think we’re probably not actually that far away from simply using npm
as a possible ClojureScript distribution mechanism - but it’s not currently in scope - shadow-cljs is probably your best bet for now.
@jazzytomato I published a post yesterday about how to get some NPM libraries playing nicely in Figwheel; might not solve all of the mapbox issues, but hopefully it'll answer a question or two: https://ajpierce.github.io/posts/react-figwheel-npm/
@thheller Hey! How much would it take to update shadow-cljs so it can build projects that use spec.alpha? What would it take?
https://github.com/thheller/shadow-cljs/wiki/ClojureScript-for-node.js-libraries is probably what you want? shadow-cljs itself is build that way
@thheller When I run it against a CLJS codebase that uses clojure.spec.gen.alpha
, it doesn’t find that namespace, even if I add spec.alpha 0.1.123 to the dependencies in shadow-cljs.edn: ExecutionException: clojure.lang.ExceptionInfo: The required "clojure.spec.gen.alpha" is not available, required by "workflo/entitydb/util/operations.cljc" {:tag :shadow.cljs.build/missing-ns, :ns clojure.spec.gen.alpha, :src "workflo/entitydb/util/operations.cljc"}
hmm yeah the alias code for some reason doesn’t work. cljs.spec.gen.alpha
works just fine
Do you want me to file a bug? I can use cljs.spec.gen.alpha in a reader conditional for now.
@thheller https://github.com/thheller/shadow-cljs/issues/74 - feel free to give it a better title, I wasn’t sure whether this is a general clojure->cljs aliasing issue or something more specific.
wrt compiler options :preloads '[my.namespace]
, is there something wrong I could be doing such that a namespace would get pulled into an :advanced
compilation, even if the configuration doesn’t list :preloads
? Would that happen if my preloaded namespace :required
another namespace in my source?
* for whatever reason my :preloads
namespace that invokes cljs-devtools always loads into my compiled app
For those interested, preloads doesn’t work the way I thought. It simply loads the namespace ahead of main.core, but it doesn’t prevent it from being loaded in case it’s not listed in :preloads
at all. In addition to this, binaryage/cljs-devtools doesn’t work with DCE unless it’s setup very specifically. (either behind a goog.DEBUG, or more preferably configured via the specific namespace [devtools.preload]
.
So my issue was that 1) cljs-devtools wasnt configured properly and 2) DCE doesn’t happen “automagically” via the lack of a :preloads to your namespace. Your namespace will still be loaded, and if you want dev-only side effects they still need to be hidden behind (when goog.DEBUG ...)
.
@jannis in case you are interested. the shadow-cljs
package is generated by this config: https://github.com/thheller/shadow-cljs/blob/master/shadow-cljs.edn#L28-L39 into this dir: https://github.com/thheller/shadow-cljs/tree/master/packages/shadow-cljs
be careful if you are building multiple libraries that way, they won’t be able to interact with each other
Got it. I may want to build two libraries like that but I can use them in isolation with a JS bridge inbetween.
Right, I see. So, if I were to enable :infer-externs
, I'll get some extern files generated for me? The way I read it, the compiler will just tell me the externs I'm missing (which is still helpful!).
@dnolen Does this allow Closure to optimize my third party JS deps, and their deps, etc? That is, the extern inference extends to the JS side, not just the CLJS side?
there are some bugs, and some use cases don’t quite work great (singletons like jQuery)
I suspect for at least the next year it will require a lot of interacting with JS lib maintainers to make small tweaks
For a react native project, I have about a dozen rn libs I'm using directly from npm; those are my only third party js deps. Should I go the :npm-deps
route, or the :infer-externs
route?
you don’t need :infer-externs
for React Native technically - advanced compilation isn’t all that important in that environment
are you suggesting we force our users to download a 4mb app instead of a 2mb app?! how barbaric 😃
Hm, due to a bug with RN specifically, :advanced
would be needed, since it makes the JS significantly smaller.
Basically, some process in RN bundling is parsing the ~4MB (`:simple` optims) JS file and timing out.
The time it takes to parse appears to at least be exponential, so we were really hoping to shrink it down in any way possible.
@jeaye hrm I haven’t heard anything about this you probably want to bring it up in #cljsrn though - I don’t follow RN that much
@dnolen Right, let's assume that I've done the necessary research and this RN bug is very difficult to fix and likely easier to work around. It sounds like :infer-externs
is best way to get :advanced
working so I can significantly shrink my JS size?
When writing macros for CLJS in Clojure, and the emitted code should include namespaces that only exist in CLJS, i.e. can't be required into the macro-defining Clojure namespace, is there a less tedious way than to manually fully namespace qualify each symbol that has a CLJS namespace? For example
`(f (cljs.core.async/alts! ...))
etchmm, I usually tend to expose macros to my cljs code via a “gateway” cljs namespace, and make sure that the “gateway” cljs namespace requires all possibly required cljs namespaces for code generated from all possible macros… this removes burden from users of my macros to remember what namespaces to require
@darwin Oh, yeah that seems good. But my problem is that in the macro itself I have to fully qualify everything.
macros return “forms” as data, so you could be able to write some generic function to walk that data and rewrite clojure-specific namespaces to cljs namespaces depending on current environment
once I wrote this to avoid writing platform-specific code for try-catch: https://github.com/binaryage/env-config/blob/master/src/lib/env_config/impl/macros.clj
npm offers :peerDependencies to say “i need this library of this version but I will not include it myself”, does cljs offer something similar? I would imagine something like maven’s :scope "provided"
but I’m not so sure that’s working as I expect.
I end up calling do a dispatch
with re-frame that calls a function that does a dispatch-sync
down the line
I want to kick off the function call in a way that says we're done with the dispatch
and have the function run without further relations to the calling handler
what are you trying to do @deadghost? generally dispatch-sync is reserved for 1 dispatch at the very beginning of the bootstrap, and then maybe for unit testing
that’s not a scenario I find myself in, but you might want to take a look at https://github.com/Day8/re-frame-async-flow-fx or https://github.com/Day8/re-frame-forward-events-fx or more generally https://github.com/Day8/re-frame/tree/master/docs#dominoes-2-and-3---event-handlers
so when the url changes, the boot handler gets called with dispatch-sync before the mount fn is called
I'm not familiar with forward-events-fx though so maybe that's what I want, idk, looking
@dnolen @anmonteiro Hey guys I just saw you committed a fix for CLJS-2279. Thanks for being so reactive. I brought this up yesterday, less than 24 h and a fix. So cool, thx again.
yep core.async did the trick, need to get around to wrapping it in a custom -fx though but whatever
Anybody know if there is a way to make ES6 class methods directly delegate to a Clojurescript implementation ns? By “directly”, I mean I would like to just have something like foo: my.delegate.foo
or some such, rather than foo() { my.delegate.foo() }
. (not even close to a JS expert, in case it isn’t obvious). The idea is to have something like gen-class with :impl-ns, if that makes sense. The ES6 class would be generated (from Clojure code), and delegate to a user-defined implementation ns. Works fine with pre-ES6, trying to figure out how to do same without writing ES6 class code in pre-ES6 syntax.
somehow I’m not surprised. boy, I hate to have to figure out how to write ES6 classes in pre-ES6!
er, I guess the advice is to not spend a whole lot of time trying to do it as I described?
if I have foo() { my.delegate.bar(); }
in my ES6 class, would calls to foo
get optimized away in :advanced (converted to calls to my.delegate.bar()
)?
If your class is something like:
class Fooer {
foo() { my.delegate.bar(); }
}
...I think you should be able to do:
Fooer.prototype.foo = my.delegate.bar;
...if you're worried about the extra function wrapper. (Though I guess it's not exactly the same if you want to make sure you receive zero arguments.)i.e. class Fooer {} Fooer.prototypep.foo = my.delegate.bar
(leave the method defns out of the body, add them with prototype assignments?)
that sounds like a great idea, at least to experiment with. reading the google on how to express ES6 classes in pre-ES6 gave me a headache. But I think the only ES6 I really need is class Foo
. maybe.
So I'm sending a request to my rest service for some information that it fetches from a DB and sends back to me, but it takes 2 or 3 seconds to return and I end up with a 500 server error, even though it eventually sends the information
(let [user (future
(first (filter
#(and (hs/check (:email (:params req)) (:email-hash %))
(hs/check (:password (:params req)) (:password-hash %)))
(mc/find-maps db "users"))))
auth (:auth-conf req)
exp (-> (t/plus (t/now) (t/days 30)) (to-timestamp))
token (jwt/sign {:user (dissoc @user :_id)} (pkey auth) {:alg :rs256 :exp exp})]
(println @user)
(mc/update db "users" {:username (:username @user)} {$set {:session token}})
(respond! 201 {:token token :age 2592000}))
This is the back endAnd the cljs
(go (let [response (<! (http/post (str url "create-auth-token")
{:with-credentials? false
:headers {"content-type" "application/json"}
:json-params {:email email :password password}}))
body (:body response)
token (:token body)]
(if (= nil (:token body))
"Something went wrong."
(do
(cookies/set! :session token :max-age (:age body))
(re-frame/dispatch [:set-active-panel :home-panel])))))
@mobileink you can write web components without classes just fine
@thheller I remember you mention this a while back, but I understand js/Reflect
is a little iffy?
anyway, just writing class Foo {}
and then some prototype assignments seems so much easier and more reliable than unpacking the whole mess into pre-ES6.
(i figure even if I eventually grok stuff like js/Object.create
etc. something will eventually byte me in the arse)
@mobileink if you turn that class into a function, the whole thing -is- the pre-ES6 version!:
// ES5 version
var Fooer = function () {};
Fooer.prototype.foo = my.delegate.bar;
ok, but doesn’t class
(not to mention extends
) do a bunch of other stuff, the details of which are best left unmentioned?
probably worth reading https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/create
i.e. customeElements.define
wants a class. If I can get away with class Foo
plus some assignments, then I do not need to grok the (undeniable imho) complexity of e.g. https://scotch.io/tutorials/better-javascript-with-es6-pt-ii-a-deep-dive-into-classes
This is a very significant release, https://clojurescript.org/news/2017-07-28-release-candidate
what i meant by 'just' is that anything you can do with a class, you can do with plain functions 😅
Hey guys, still playing with the new :npm-deps feature, and I ran into another problem. When I :require ["@material/textfield/foundation"]
now the code compiles (thanks to CLJS-2279). But there is now an issue at run time. The javascript files required by “node_modules/@material/textfield/foundation.js” in its es6 import statements aren’t taken into account. They don’t make it to my :output-dir
and I get in the js console of the web browser the error Undefined nameToPath for module$$material$base
@sundarj understood, not whining, thanks for the input. for the moment, I’m going to mix ES6 and pre-ES6 just to minimize the code complexity (for me at least) and see what happens. I may be back. 😉
@mobileink sounds good!
@jeremys make something minimal and report it in JIRA please - not sure if anyone will have time to look at it today, but at least it will give us something to track.
when reporting it’s preferable that the minimal case not include outside tooling - in your case your should be able to replicate the problem with the QuickStart ClojureScript JAR
for the next couple of months if you encounter :npm-deps
issues please report here first - so someone can screen it - then take it to JIRA if requested
it’s going to take a while to figure out what we should do as there so little standardization in NPM, but I believe we can cover many interesting / popular libraries
in particular we’re interested in libraries with functionality not already covered by ClojureScript or Google Closure
Excited for the new release! How would one use yarn instead of npm? Is there a :yarn-deps
flag or something like that?
my stupid question of the day: just compiled some misnamed clojurescript - file is my-app/delegate.cljs
, with namespace my-project.foo
. I believe that would blow up in Clojure? but it compiles in cljs. (following the basic instructions at quick-start) Wondering why it compiles?
@dnolen my pleasure, plus I’d really like to make these material component web stuff work and since it is a google thing it is supposed to play well with closure compiler...
@mobileink it was unclear six years ago whether we should be classpath or file system oriented - so that works - and it’s not going to change now
@colindresj no need
Oh ok, so the :npm-deps
flag is just about establishing which node modules can be used in :require
. In other words, it’s still up to us to npm install
or yarn add
@colindresj not quite
:npm-deps
is for people who don’t care about yarn
since from a ClojureScript perspective it’s not necessarily relevant - esp. in the long run
so you could depend on a CLJS library that declares an NPM dep, and then ask the ClojureScript compiler to install it via npm
tool
Ah ok, makes sense
Yeah that’s cool, just being able to set npm-deps
, then have it all work seems like the main use case
Personally don’t care too much if node modules are coming via yarn or not, but wanted to know what that would be like
@jeremys poking around on https://github.com/material-components/material-components-web, your assessment does seem correct, it looks like not only should it work Closure, but designed for it
@anmonteiro I wonder if the issue here is that module_deps.js
resolution can’t follow through ES6 import so we can’t compute the inputs to pass into Closure?
@dnolen that seems like a fair assessment
I'll look into seeing how we can solve that later
@anmonteiro looks like module-deps supports this, can transform before resolve
Cool, then shouldn't be hard to plug it in
I'm not at the computer until later but can look into it. If not today, tomorrow
O frabjous day! Thanks to @rgdelato, that beamish boy, I’ve got straighforward delegation from ES6 class declarations to cljs implementations working! Callooh! Callay! At least I think I do. If you want to play, see https://github.com/miraj-project/psk2. (this is just js/cljs for experimentation, not miraj) Note that there is a problem involving load ordering - see the NOTE in the middle of src/my-app.html
. I’ll prolly need help figuring that out, and it could end up being pretty complex once you add code-splitting and multiple webcomponents.