Fork me on GitHub
#shadow-cljs
<
2018-07-26
>
kwladyka07:07:45

shadow-cljs watch app
(shadow/watch :app)
=> :already-watching
(shadow/nrepl-select :app)
To quit, type: :cljs/quit
=> [:selected :app]
(js/alert "foo")
No application has connected to the REPL server. Make sure your JS environment has loaded your compiled ClojureScript code.
I have opened website in Chrome. What I miss?

thheller07:07:29

doesn't seem like the website has your generated JS loaded?

thheller07:07:34

anything in the browser console?

thheller07:07:45

should say shadow-cljs: WebSocket connected!

thheller07:07:35

if you want something easier to just test nrepl and stuff you can run shadow-cljs browser-repl and then (shadow/repl :browser-repl) in the REPL to select it

kwladyka08:07:31

shadow.cljs.devtools.api/find-resources-using-ns wow you are always surprising me

chrisetheridge09:07:36

is it possible to merge certain keys from a build config? for instance, i want to create a dev build that uses all of the “release” entries, plus 1 more?

bupkis09:07:02

@thheller Have you thought about using rebel-readline in the various REPLs that shadow-cljs provides?

chrisetheridge10:07:44

loader-mode eval is amazing!

thheller10:07:27

sweet. do you have before/after data? curious about the difference

thheller10:07:16

@samuel.wagen I have not. I only use the REPL from my editor so readline support doesn't do anything for me and thats why I haven't worked on anything related yet.

thheller10:07:25

it does sound cool but I didn't have time to look into it yet

bupkis10:07:34

@thheller fair enough. do you have any pointers where to start, if I want to try adding it myself?

chrisetheridge10:07:48

no concrete metrics, but i can feel the difference in the browser. before, without eval loader mode, the browser would have at least 2 seconds of lag, appending all the goog scripts. now, nothing. our “loading” symbol doesn’t even show anymore! 😄

thheller10:07:18

@samuel.wagen no idea. you can probably use it out of the box for the CLJ REPL

thheller10:07:23

but no idea how to hook up the CLJS part

bupkis10:07:05

yeah, one step at a time I guess 🙂

bupkis10:07:23

I'll try hooking it up to the CLJ part when I get some free time

bupkis10:07:33

it has CLJS support but I'd need to explore it

thheller10:07:12

I'm guessing that is pretty tightly integrated with the cljs.repl APIs which wouldn't work with shadow-cljs

bupkis10:07:06

oh well 🙂 I'm using vim-fireplace, and I find myself not liking it much and preferring to use the cljs-repl instead.

thheller10:07:07

btw you can open while shadow-cljs is running

Jon11:07:34

no "eval" button?

thheller11:07:52

shift+enter

Jon11:07:17

tried "command enter"...

Jon11:07:23

wrong guess

thheller11:07:00

yeah UI/UX currently sucks. I just wanted to test some stuff and it works ok-ish

Jon11:07:17

looks good

thheller10:07:20

while that is currently very basic it has parinfer support

thheller10:07:34

I'll probably work on adding history support, completion and all that stuff at some point

thheller10:07:47

I think that makes for a way better interface than a stupid command line

thheller10:07:13

its basically only a proof of concept currently though

bupkis10:07:39

I know of it, but I prefer a terminal split instead of yet another browser window/tab - it's less context switching for me.

thheller10:07:10

thats why I do have plans for a chrome extension which would put the REPL into your browser devtools 😉

thheller10:07:20

ie. not a tab

bupkis10:07:44

that would be cool to have, for sure. for my use case though, I love the cljs-repl feature of showing the println output in the repl in addition to having it in the devtools console - helps me use devtools less and stay nearer my editor

bupkis10:07:06

I have tried several times to switch to Emacs for the better integrated REPL, but it's just not for me, even with evil-mode. Anyway, that's irrelevant. Maybe I'll be able to add some more creature comforts to cljs-repl even without directly using readline-rebel

thheller10:07:07

well I do have plenty of plans for all of this but just not enough time to actually do it

thheller10:07:20

so if you figure out how to hook up the rebel-readline stuff let me know

bupkis10:07:41

ain't that the case with all of us 🙂 in any case, your efforts are greatly appreciated, shadow-cljs has been much more pleasant experience than the alternatives, at least for me

bupkis10:07:48

will do, for sure

kwladyka12:07:48

https://github.com/ethereum/web3.js

(ns boilerplate.example-test
  (:require [cljs.test :refer [deftest is testing use-fixtures]]
            ["web3"]))

(println (pr-str (js/Web3.)))
How to do:
var Web3 = require('web3');
var web3 = new Web3();
I was trying a few ways, but always ReferenceError: Web3 is not defined

p-himik13:07:43

@kwladyka It should be available as js/web3, lower-case.

kwladyka13:07:55

it is not 😞

p-himik13:07:15

Ah, it also supports require - I didn't notice. Wait a sec.

p-himik13:07:39

@kwladyka You use version 14, right?

kwladyka13:07:42

hmm npm i web3 did this: "web3": "^1.0.0-beta.35" I didn’t notice it

p-himik13:07:07

Well, in 0.14.0 you should be able to use (:require ["web3" :as web3]) in your ns definition.

p-himik13:07:21

Maybe 1.0.0-beta.35 backwards-compatible in this regard.

p-himik13:07:43

Well, if you want to use beta at all.

kwladyka13:07:09

(ns boilerplate.example-test
  (:require [cljs.test :refer [deftest is testing use-fixtures]]
            ["web3" :as web3]))

(println (pr-str (js/web3.)))

kwladyka13:07:13

the same issue

kwladyka13:07:19

with right version

p-himik13:07:29

No-no, no need for js/.

p-himik13:07:32

Just web3.

kwladyka13:07:06

web3. with .?

kwladyka13:07:17

ok I have progress #object[Web3 [object Object]]

kwladyka13:07:25

thanks

👍 4
kwladyka13:07:49

console.log(web3); // {eth: .., shh: ...} // it's here! Can I print it without webrowser?

kwladyka13:07:11

instead of #object[Web3 [object Object]]

p-himik13:07:32

Not sure I understand. You mean you want the contents, not the [object Object], and you're using CLI, not a browser console?

kwladyka13:07:18

shadow-cljs watch node-test <- at that moment i am running tests, so it is not in web browser

kwladyka13:07:42

web3 says I can do console.log(web3) to print it

kwladyka13:07:59

but (println …) in cljs print #object

p-himik13:07:51

You can try (js/console.log web3). If that doesn't change anything, there should be other members of js/console, like dir. But I have no idea whether they're supported during the test run.

kwladyka13:07:32

oh it works… just like that

kwladyka13:07:39

I expected it would be harder

kwladyka13:07:41

thanks again

👍 4
p-himik13:07:41

@thheller How bad is it to override functions defined in some other ns? Will it work? Will it be predictable? I have some issues with Reagent, and I really don't want to include the whole library just to change a couple of functions.

p-himik13:07:10

I've found cljs.core/find-ns-obj, but it's in the section titled "Bootstrap helpers - incompatible with advanced compilation". I have no idea how exactly they're incompatible though - they appear to use munge, so at least symbol names should be correct.

p-himik13:07:45

Ah, munge has nothing to do with the advanced compilation...

kwladyka13:07:27

Why not make your own code which use reagent? It sounds a little like a bad idea.

p-himik13:07:14

@kwladyka If you're interested, you can take a look at https://github.com/reagent-project/reagent/issues/389 for more details. In essence, these functions that I'd like to change are used deep inside Reagent, so I can't just add my own implementation and tell Reagent to use it. I don't plan overriding to be a long-term solution. More like a piece of plumbing until the issue is fixed.

kwladyka13:07:14

hmm Do js class need #js format instead of clsj? That is why it is converted. No idea, but it sounds reasonable.

p-himik13:07:41

The problem there is that all CLJS data passed to a wrapped React component is being converted into JS data structures. The issue is that it's impossible in the general case to convert the data back because CLJS->JS conversion is lossy.

kwladyka13:07:07

> CLJS data passed to a wrapped React component is being converted into JS data structures. No reason for that?

p-himik13:07:48

Well, there's definitely a reason - just as you wrote yourself. The issue is that it's a reason for most of the cases, but definitely not for all of them. E.g. my component is not a true React component, but rather a wrapped Reagent component, so not only do I not need the conversion, but it straight spoils everything.

kwladyka13:07:24

hmm not sure what you want achieve in practice, but are you sure adapt-react-class is right function then? It sounds like you want use it with other purpose, than it was created.

p-himik13:07:23

What do you mean? The pure React wrapper that I want to use returns a React class, so I have to use adapt-react-class. And it also accepts only a pure React class, so I have to use reactify-component.

kwladyka13:07:56

ok, sorry I can’t help. I was using it only for js modules

thheller13:07:58

@kwladyka (:require ["web3" :as web3]) and then use web3 without js/.

thheller13:07:47

@p-himik overriding a var from a different namespace is absolutely not recommended

thheller13:07:17

you can instead just take the original source file and put it in your source path with the changes you want

p-himik13:07:49

@thheller Yeah, I was thinking about that. But how do I make sure that my file has priority?

thheller13:07:30

source path always as priority

p-himik13:07:45

Oh, that's good to know, thanks!

thheller13:07:08

only works in your project though. can't do that with libraries

p-himik13:07:27

But hypothetically - would something like (set! reagent.core/adapt-react-class (fn [c] ...)) work? Wait, what do you mean? Either I don't understand something, or your statement contradicts with what you already said.

thheller13:07:37

it sort of works yes but you must ensure that the thing you are adding has the exact same signature as the original

thheller13:07:48

ie. can't do that with muilti arity fns

p-himik13:07:54

Oh, I was trying to change signature, heh.

thheller13:07:03

yeah the set! won't update the compiler/analyzer data so it may emit code that isn't compatible

thheller13:07:34

back to the override issue: it works in your project since the project sources paths come first before the jars on the classpath

thheller13:07:41

if you however package all your code up into a jar

thheller13:07:11

since your jar will depend on reagent the reagent jar will be loaded first

thheller13:07:22

so it takes priority then

thheller13:07:38

however its totally fine in an uberjar again

p-himik13:07:51

So is in a single JS, right?

p-himik13:07:22

I don't deploy jars, I run the build on target servers.

thheller13:07:31

thats fine yeah

p-himik13:07:58

Great, thanks!

thheller14:07:56

@kwladyka the code to match the JS example would be

(ns boilerplate.example-test
  (:require [cljs.test :refer [deftest is testing use-fixtures]]
            ["web3" :as Web3]))

(def web3 (Web3.))

kwladyka14:07:56

@thheller thank you, @p-himik already showed me it in thread 🙂

thheller14:07:48

ah ok didn't see that

lilactown14:07:25

the more I use reagent, there are some things I love about it (the ability to represent my component tree as dumb vectors) and some things I hate (all of the magic)

lilactown14:07:33

if they had not included their own async rendering and special reagent classes then it would be so much more flexible. but perf would probably be terrible

thheller14:07:18

but perf is terrible because of the dumb vectors which you like 😉

thheller14:07:06

to me (html/h1 "hello world") looks just as nice as [:h1 "hello world] but doesn't require vectors->reactelement translation

lilactown14:07:25

lol. well I wrote my own macro that turns the dumb vectors into function calls

lilactown14:07:52

but then I started to wonder what the point was 😛 I'm starting to coming around to the parens (div "foo")

lilactown14:07:57

but we actually use the fact that the runtime representation of a reagent component is just a vector a lot at work

lilactown14:07:32

it turns out that it's much easier to traverse and transform than an actual React tree

thheller14:07:11

also much slower though 😉

thheller14:07:37

well traversing and transforming vs. not doing that

lilactown14:07:13

true 😛 but there are usecases

lilactown15:07:33

we're doing server rendering of react components on Node.js, and are using the apollo library to do queries to a graphql endpoint. on the server side we traverse the tree, fetch all of the data necessary to render it, and then call render-to-string. using reagent + cljs it's a simple clojure.walk algorithm with some clever binding. with pure React it would involve calling the render function or calling a special getData method (which dan_abramov admonished the community for)

thheller15:07:42

or you use the om.next/fulcro approach and don't worry about react at all 😉

lilactown15:07:20

apollo is basically relay++ 😛 and tbh the reason I had to write my own SSR stuff is because we're using reagent and not apollo-react...

lilactown15:07:49

but om.next & fulcro didn't really fit our use case. we wanted to go all-in on React, and also we're not building an SPA

thheller15:07:23

or I think the relay guys do that as well

lwhorton15:07:35

hmm… i know shadow can read json files, since it first goes to a lib’s package.json and traces from there. but what the heck might this be? The required JS dependency "node-releases/data/processed/envs.json" is not available, it was required by "node_modules/browserslist/index.js" . my dependency postcss has a dep on browserslist, which has a dep on node-releases (which exposes the envs.json file). a double transient dependency resolution 😞

thheller15:07:57

@lwhorton do you have a node_modules/node-releases/... directory?

lwhorton15:07:27

indeed, it was installed after i installed postcss (which lists the dep tree i mentioned)

thheller15:07:30

because that file exists for me?

thheller15:07:30

[1:1]~cljs.user=> (require '["browserslist" :as x])
nil
[1:1]~cljs.user=> x
#object[browserslist]

thheller15:07:35

compiles and loads fine

thheller15:07:08

but you shouldn't try to compile postcss for the browser

thheller15:07:11

thats a really bad idea

thheller15:07:22

the last time I checked it was gigantic

lwhorton15:07:08

ugh *shakes fist* ie11

thheller15:07:21

hmm my browserslist version doesn't load the envs.json

lwhorton15:07:14

yea i think that’s the same error i’m getting. the envs.json file is definitely there, and the require statement in browserslist is pointing to the right file

thheller15:07:16

hmm or its just filtered out. thats odd

dijonkitchen16:07:13

How does :npm-deps compare to shadow-cljs?

souenzzo17:07:25

is possible export a js bundle that will be used in a template-like website (PHP/django that use many <script src=...> ), without risk to conflict with another bundle?

thheller17:07:04

@souenzzo sure it should work by default. Its just not recommended to make multiple independent CLJS builds like that and loading them since each will contain their own cljs.core version which would not be compatible with each other

thheller17:07:24

if you only have one however CLJS build and the rest is non-CLJS that is not a problem

thheller17:07:53

@dijonkitchen shadow-cljs only compiles npm dependencies with :simple optimizations. :npm-deps tries to do :advanced. If that works its better but it rarely works so shadow-cljs sacrifices that for more compatibility.

dijonkitchen17:07:18

Yeah, I’ve had trouble with :npm-deps but it should work, at least for simpler cases. Why does it rarely work?

lilactown17:07:26

:thinking_face: can I have two separate bundles (they're on separate pages) with the same module identifier?

souenzzo17:07:52

@thheller I just need to delivery one script src='...' with one function. But I dont know anything about the other scripts that this site will use.

thheller18:07:51

@dijonkitchen it rarely works because the mess of JS that is on npm. they don't follow the closure JS standards at all and sometimes to some dynamic stuff which the closure compiler doesn't understand. also the commonjs support is a bit lacking in places and some idioms the JS folks use are not supported at all.

thheller18:07:26

shadow-cljs basically follows the model of webpack instead and matches that much more closely since most JS libs are sort of tuned for that

👍 4
thheller18:07:50

@lilactown what module identifier? if you mean :modules no, that must be unique.

lilactown18:07:03

yeah i mean :modules

thheller18:07:13

@souenzzo thats fine then if you lib doesn't interact with the other ones

lilactown18:07:38

e.g.

:dashboard
{:target :browser
 :modules {:main {...}
           :onboarding {...}}}

:other-page
{:target :browser
 :modules {:main {...}
           :onboarding {...}}}

souenzzo18:07:22

@thheller the main cljs compiler/the closure compiler itself has problems if there is 2 bundlers imported in the same browser #shadow-cljs solves that?

thheller18:07:07

the :output-wrapper solves that. CLJS also supports that though.

thheller18:07:05

@lilactown thats two different builds, thats fine if you use different :output-dir values

thheller18:07:30

but if the user will jump between dashboard and other-page frequently

thheller18:07:08

you should look into :app {:target :browser :modules {:common {...} :dashboard {:depends-on #{:common} ...} :other-page {....}} instead

lilactown18:07:30

yeah I haven't quite shook out how I want to structure it yet

lilactown18:07:45

right now we only have the one page, just trying to think ahead

thheller18:07:29

yeah getting :modules just right is tough. always consider how the user moves though.

thheller18:07:42

when I started with modules I had one gigantic build that included everything

thheller18:07:00

and would just have a module for :admin stuff and then one per page and so on

thheller18:07:32

but the user would never access :admin and some of the stuff in there made the base modules larger

thheller18:07:46

so it was much better to have a separate :admin build and keeping that out of normal user stuff

thheller18:07:28

but if :dashboard and :other-page are both used by the user (in the same session)

thheller18:07:32

then those should be modules

thheller18:07:33

@souenzzo you can either do (defn ^:export your-fn [...]) to have your function accessible from HTML via <script>your.ns.your_fn();</script>

thheller18:07:15

or you can use (defn your-fn [...]) (js/goog.exportSymbol "yourFn" your-fn) to have it accessible as <script>yourFn();</script>

thheller18:07:16

I'd suggest doing the second. otherwise you need to ensure that the NS you use doesn't clash with anything on the page, ie. ensure there is no your variable in the example above

souenzzo18:07:58

Nice! There is some "formal" docs about it?

thheller18:07:36

no idea, probably

eoliphant23:07:45

Hi, i’m trying to ‘transate’ some react jsx code over to cljs I read through the section on using babel to convert jsx’es to .js, got that working. but imports of other resources just work? Here’s a snippet

import "perfect-scrollbar/css/perfect-scrollbar.css";


import withStyles from "@material-ui/core/styles/withStyles";


import Header from "components/Header/Header.jsx";
import Footer from "components/Footer/Footer.jsx";
import Sidebar from "components/Sidebar/Sidebar.jsx";

import dashboardRoutes from "routes/dashboard.jsx";

import appStyle from "assets/jss/material-dashboard-pro-react/layouts/dashboardStyle.jsx";

import image from "assets/img/sidebar-2.jpg";
import logo from "assets/img/logo-white.svg";
So I get that after running babel I should be able to do something like (require ["components/Header/Header" :default Header]) but does this also work for the css, images and what have you? like (require [ "perfect-scrollbar/css/perfect-scrollbar.css"])

justinlee23:07:13

@eoliphant importing non-js resources like that doesn’t work in shadow-cljs (it’s a webpack-specific extension)

eoliphant23:07:34

that’s what I was thinking/wondering lol

justinlee23:07:36

just include css directly in your html

eoliphant23:07:11

ok so, for this component level style stuff?

justinlee23:07:39

webpack has a bunch of “loaders” that bundle up resources for you. people can get a bit obsessed with reducing the # of round trips a page load takes, but the reality is you can always bundle all your css into a single file using less or sass, so at most it is a single additional tag

eoliphant23:07:24

this is a lib/tempate

justinlee23:07:31

in my index.html, I just have a <link rel="stylesheet" href="/css/site.css"> in my <head> tag

eoliphant23:07:31

so I could just scan the dirs?

eoliphant23:07:49

and to grab all the .css files

eoliphant23:07:00

to mush them into an uber css or something?

justinlee23:07:07

that’s what I do

justinlee23:07:26

i’m sure there’s something more sophisticated, but that solution is simple and it works

eoliphant23:07:38

i like simple lol

justinlee23:07:44

yea me too 🙂

eoliphant23:07:16

i understand the rationale for this approach but it seems kind of ‘noisy’ lol

eoliphant23:07:20

so these jss files or whatever shold just work as they’re javascript?

justinlee23:07:31

god css is so terrible. I had been @importing library css into my main scss, but now it is deprecated. https://github.com/sass/libsass/issues/2611 The only clear solution is ‘use webpack’ (?) lol

justinlee23:07:59

i don’t know what jss is

eoliphant23:07:12

it looks like .jsx files with style info

eoliphant23:07:47

import {
  drawerWidth,
  drawerMiniWidth,
  transition,
  containerFluid
} from "assets/jss/material-dashboard-pro-react.jsx";

const appStyle = theme => ({
  wrapper: {
    position: "relative",
    top: "0",
    height: "100vh",
    "&:after": {
      display: "table",
      clear: "both",
      content: '" "'
    }
  },
  mainPanel: {
    transitionProperty: "top, bottom, width",
    transitionDuration: ".2s, .2s, .35s",
    transitionTimingFunction: "linear, linear, ease",
    [theme.breakpoints.up("md")]: {
      width: `calc(100% - ${drawerWidth}px)`
    },
    overflow: "auto",
    position: "relative",
    float: "right",
    ...transition,
    maxHeight: "100%",
    width: "100%",
    overflowScrolling: "touch"
  },
  content: {
    marginTop: "70px",
    padding: "30px 15px",
    minHeight: "calc(100vh - 123px)"
  },
  container: { ...containerFluid },
  map: {
    marginTop: "70px"
  },
  mainPanelSidebarMini: {
    [theme.breakpoints.up("md")]: {
      width: `calc(100% - ${drawerMiniWidth}px)`
    }
  },
  mainPanelWithPerfectScrollbar: {
    overflow: "hidden !important"
  }
});

justinlee23:07:49

that seems bad. surely there a distribution-friendly version of the library

justinlee23:07:08

libraries should haven’t jsx and inline css and crap like that. most library ship with compiled code

eoliphant23:07:17

it’s like an add-on for mui

eoliphant23:07:43

but everything is source

justinlee23:07:26

it’s just not going to be easy to make that stuff work with cljs without a build step. as i’ve said to thheller before: people don’t program in javascript anymore, they program in webpack. but most people are decent enough to build their code into something portable before shipping to npm

eoliphant23:07:44

yeah it’s not in npm it’s commercial

eoliphant23:07:55

ugh webpack lol

justinlee23:07:18

the import "thing.css" is webpack. the jsx needs a babel transform

eoliphant23:07:22

well at least it comes with a config

eoliphant23:07:36

for babel, webpack etc

eoliphant23:07:43

so i can use those as a starting point

justinlee23:07:00

so many people use the webpack/babel stack that code is starting to assume that you are too. so you’ll need to set up a build step before using with cljs

eoliphant23:07:32

yeah i’d already figured that, since shadow doens’t compile .jsx

eoliphant23:07:42

so will just add the other crap as well lol

eoliphant23:07:50

presumably this node-sass-chokidar thing is tackling the css, also doesn’t look like it uses webpack (directly at least), it’s using react-scripts for the build

"build-css": "node-sass-chokidar --include-path ./src --include-path ./node_modules src/ -o src/",
    "watch-css": "npm run build-css && node-sass-chokidar --include-path ./src --include-path ./node_modules src/ -o src/ --watch --recursive",
    "start-js": "react-scripts start",
    "start": "npm-run-all -p watch-css start-js",
    "build": "npm run build-css && react-scripts build",

justinlee23:07:47

that will build the css, but it won’t strip the webpack loader extensions out of the code. i.e., you’ll still have the import “blah.css” in the code, and that is going to make the js runtime choke

eoliphant23:07:54

ah.. hell… so what fixes that?

justinlee23:07:18

one of the css loaders in the webpack config will. if it already comes with a config, then it should be good to go

eoliphant23:07:24

so the babel plugin will leave that stuff in?

eoliphant23:07:41

it doesn’t look like it does