This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-09-26
Channels
- # 100-days-of-code (3)
- # announcements (2)
- # beginners (237)
- # bitcoin (2)
- # boot (5)
- # cider (15)
- # cljs-dev (9)
- # cljsrn (6)
- # clojure (75)
- # clojure-estonia (1)
- # clojure-italy (8)
- # clojure-losangeles (1)
- # clojure-nl (1)
- # clojure-spec (68)
- # clojure-uk (80)
- # clojurescript (89)
- # cursive (31)
- # datomic (22)
- # emacs (2)
- # events (3)
- # figwheel-main (184)
- # fulcro (28)
- # graphql (1)
- # hyperfiddle (2)
- # jobs (1)
- # jobs-discuss (64)
- # luminus (5)
- # off-topic (16)
- # om (2)
- # onyx (1)
- # pedestal (12)
- # portkey (1)
- # re-frame (13)
- # reagent (56)
- # reitit (13)
- # ring-swagger (13)
- # shadow-cljs (145)
- # slack-help (2)
- # specter (6)
So I got all of my development environments setup, but i'm wondering if my workflow is wrong. In all of the cljs repls, it starts out in the namespace cljs.user, so I have a cljs/user.cljs file that contains some code. Only problem is, it doesn't appear to have my functions that I wrote in there (reloaded workflow) until after i've edited a file. I've noticed this behaviour in both my node build and my browser build. Is there a different way I should be preloading development tools into the cljs repl?
Was able to solve this by pointing :main at cljs.user and pulling in my original dev environment.
@bhauman thanks for looking into this, but I'm starting to doubt we'll be able to use it. We're using a custom list of foreign-libs
for the node build to exclude a whole bunch of cljsjs
dependencies, which on node we load directly from node_modules instead. Unless we come up with a different solution there I think we'll have to keep the build separate.
Trying out the :ring-handler
config option, I discovered that the fn I specify seems to acts as a fallback handler, rather than replacing the default ring ahdnler.
My handler looks like this
(defn handler [{:keys [request-method uri]}]
(if (and (= :get request-method)
(or (= uri "/app") (str/starts-with? uri "/app/")))
(ring.response/resource-response "index.html" {:root "public"})
{:status 404
:headers {"Content-Type" "text/plain"}
:body "Not Found!"}))
But the handler isn't called when I request /index.html
, i.e. something that is on a valid resource on the class path
Is that the expected behavior?
So the handler is invoked for /index.html1
but not for /index.html
(which exists)
The handler is also not called for /
, which caught me by surprise
@pesterhazy yes static resources shadow the handler
It looks like /
defaults to index.html, if one exists
all the logic is here https://github.com/bhauman/figwheel-repl/blob/master/src/figwheel/server/ring.clj
Personally I find this nonobvious
Especially given that it's so easy to implement the fallback myself
But I guess figwheel needs to serve the .js
files as well?
of course, I understand
@pesterhazy but if you want to whole hog take over the server, I’m happy to add an option for that
@pesterhazy you can also customize the :ring-stack
you normally wrap your ring-handler as the final handler and the resource handler comes before it
@plexus I did some experimenting this morning and I have :target :nodejs
working for extra mains and I have the node and web targets sharing a webpack bundle so that the requires stay consistent for shared web and node code
of course I only did this for one library on a simple demo project, I’m not sure how it would stand up against a large project, I also wouldn’t expect Nodejs corner cases to be compiled correctly
@bhauman we (I’m working with @plexus on this) probably need to do some work to unify our node target with others regarding foreign-libs first.
we’ve been able to collapse five builds into one. We jumped through some hoops before to keep the feedback cycles down (figuring out what needs to be rebuilt and providing options to switch builds on and off) and that code could all go away now.
@bhauman I think it would be great to have a way to truly override the default ring handler, especially for /
. But mainly I think the documentation could be amended to note that the handler is a fallback, not the primary handler
I guess it would be possible to provide a :ring-handler-override
option that can return nil, in which case the figwheel handler kicks in
using the ring convention, (or (handle1 req) (handler2 req) (handler3 req))
and I kinda feel like if you use ring-handler-override it should be an override and not an or relationship
@pesterhazy did you see my comment on how this is how folks normally use ring-defaults? and how they normally wrap around the api-ring-handler?
I saw that comment but I guess I didn't understand it
I’m just saying that its common for the static resource handler to come before the api handler
maybe it's best then to just make the docs a bit more explicit
if I built my own web server, is there a simple example of how to hook into figwheel to serve the compile artifacts?
happy to make a docs PR if that's desirable
@pesterhazy when you have your own server, you serve the compiled artifacts
I just serve them out of target/
?
right, I'm guessing I don't get the benefit of Figwheel's clever caching defaults etc then
gotcha
to be clear, the way it works today works well for my use case, it just took me like 30min of debugging to figure out how it works
it's the kind of thing that, as an experienced web developer, you really want to understand the serving logic exactly
(plus for the beginner it should "just work")
right, I was talking about development time
but if you are starting to add a server it normally is better to create your own server, that way you do get control, and as a bonus you have something you can deploy
in my view, the best way to deploy a SPA in 2018 is not to mess with servers at all
S3 + CloudFront does that job for you
today I learned that you customize the behavior of CloudFront to precisely define the routing logic
the lambda actually hooks into CloudFront directly - it's called Lambda@Edge
so it's javascript that runs in the Edge region - it's like Apache's mod_rewrite, except you write real code
it's a bit annoying to set up at first, but very powerful when you get the hang of it
AWS is going to get total buy in, the idea that you can write something that will run on any cloud service is pretty much over in practical terms
yeah I don't like to think about an additonal abstraction layer on top of aws
to be fair, other CDN providers like Fastly or Cloudflare give you Edge-side workers as well
yeah depends on your requirements
to me the important take away is that static assets belong on S3 (or the GCP equivalent)
then you can serve them off S3 directly, or using a CDN, or using nginx or a similar reverse proxy
that simplifies the whole process a lot
example of a Lambda@Edge script for URL rewriting for SPAs: https://gist.github.com/pesterhazy/05639a992fdaa965464e7ce680832712
personally I’m really excited by the fact that I have :extra-main-files working for a Node target alongside a web target
we actually have a use for that as well, that's pretty cool
well I wouldn't use webpack for node, that's pretty unusual
right hm...
I guess you could use global exports with a simple file that goes
global.moment = require("moment");
- no webpack needed for that right?you'd need a separate package.json for the node part of your app (but you'll need separate deps anyway)
this is quite relevant to our interests as well... we share a bunch of code between node and frontend, and quite often cljsjs packages get pulled in by libraries (or by us) that are not compatible with node
@pesterhazy yeah that would work
googl.global.Moment = ... wouldn't go thru advanced compilation, being a foreign lib right?
@plexus I think for node I wouldn't use cljsjs if possible
package.json, (def fs (js/require "fs"))
-> works
right right
that's quite rare in my experience though
moment is an example that makes sense
you could always use (def moment (if (exists? goog.global.moment) goog.global.moment (js/require "moment")))
not pretty, I know, but maybe acceptable for one of two libs
@pesterhazy for context, we have a "renderer" node process that runs our Reagent views on the backend to pre-render them. Reagent pulls in cljsjs.react, there are I think about two dozen of these cases. We work around it with a fake :foreign-libs
entry that "provides" cljsjs.react
, and load react from node_modules
instead, but it's a fidgety approach. I'm curious if there would be a better alternative.
I think loading react from node_modules is the right approach
@plexus maybe a look at this repo helps: https://github.com/pesterhazy/cljs-spa-example/blob/master/deps.edn#L7
and https://github.com/pesterhazy/cljs-spa-example/blob/master/doublebundle/library.js
obviously this uses Webpack, which I wouldn't recommend for Node
I don't think you need to provide cljsjs.react anymore, you just need to supply an exclusion
var goog = goog || {global: window};
import * as moment from 'moment';
goog.global.Moment = moment;
when you deploy Node you could use a npm index.js file for your global exports instead of the webpack bundle
I’ve written an introduction and now I’m working on a decent guide on how to get up and running with emacs
var goog = goog || {}
- is that safe?
> var w = v || {}
ReferenceError: v is not defined
> var v = v || {}
undefined
I don't understand JS after all these years
how is the first different from the second?
it only works if it's the same var left and right of the equals sign
maybe the var is already in scope (but undefined)
I believe you, I'm only in disbelief about how I didn't know that before
yeah, I've definitely seen that pattern in the wild before
@bhauman If you haven't gotten to it yet, I have time this morning to write up the basics of how I've got Cursive working nicely with figwheel-main
@shaun-mahood yeah that sounds great
Yeah - do you want me to work from a particular starting point (like the lein template)?
The other doc I think I'm ready for is using figwheel with Integrant, so I will try and get something on that afterwards.
Sounds good, I'll try to follow the existing docs as much as I can
@shaun-mahood Thanks! That sounds awesome.