Fork me on GitHub
#shadow-cljs
<
2019-05-14
>
wilkerlucio01:05:39

I'm trying to use this library https://rete.js.org/#/, but seems like it depends on some webpack magic to work, when I try to require it I get

js.js:133 Uncaught ReferenceError: regeneratorRuntime is not defined
    at rete.common.js:418
    at rete.common.js:415
    at Object.shadow$provide.module$node_modules$rete$build$rete_common (rete.common.js:396)
    at Object.shadow.js.jsRequire (js.js:122)
    at Object.shadow.js.require (js.js:158)
    at com.wsscode.wise.client.ui.rete.core.js:5
, I guess it may be some webpack polyfill, not sure, is there any way around it?

mss01:05:32

is there syntax for specifying a local cljs dependency for a shadow-cljs project similar to lein-install?

wilkerlucio01:05:49

@mss not directly, but you can add directly to the source-paths, or use deps.edn, its local deps support works with shadow

mss01:05:27

will do, appreciate the help

vinurs07:05:48

hello, i’ve a question that lein shadow doesn’t read the ~/.shadow-cljs/config.edn ?

thheller07:05:00

@haiyuan.vinurs lein-shadow is a 3rd party project I have no control over and no it does not read that config

thheller07:05:21

I assume you mean for it to pick up the :dependencies listed there?

thheller07:05:47

you'll need to list that in the project.clj

vinurs07:05:22

yes, i’ve tried that and it works ok, so i found the problem, so i ask this question

vinurs07:05:49

sorry i don’t know this is a 3rd party project, i’ll look at it

thheller07:05:39

I recommend using the regular shadow-cljs cmd. you only lose functionality by moving to lein-shadow and gain absolutely nothing (IMHO)

caleb.macdonaldblack09:05:38

What would be the right way to do dev dependencies in shadow-cljs without leiningen?

caleb.macdonaldblack09:05:48

And dev source paths

thheller09:05:07

not supported

caleb.macdonaldblack09:05:59

If I put them under :dependencies would that bloat my production build?

thheller09:05:34

no, :dependencies have no affect on the build size

thheller09:05:45

the build decides what ends up in it not the classpath

thheller09:05:47

@caleb.macdonaldblack when building :browser targets always check the build reports https://shadow-cljs.github.io/docs/UsersGuide.html#_build_report

👍 4
kenny16:05:39

Does a Build Report compile the app or does the app need to be compiled first?

thheller16:05:54

@kenny it'll do a release build. no need to compile it yourself

kenny16:05:08

Cool. Can it use an existing build to run faster?

thheller16:05:31

well. it'll use the cache of release builds yes

thheller16:05:08

so yeah doing a release first will actually make the build report faster

thheller16:05:40

but might actually not

kenny16:05:42

Hmm. Just added it to my CI and it actually takes 1s longer to run than the release build.

lilactown16:05:55

what can i pass to (shadow/release) to tell it to use simple/none optimizations?

thheller16:05:23

hmm yeah the build reports do kinda require their own thing since they adjust some settings to get all the necessary info

thheller16:05:36

and those may actually hurt the normal release cache

thheller16:05:05

@lilactown :none is not possible. otherwise just set the usual :compile-options {:optimizations :simple}

lilactown16:05:28

so (shadow/release {:compile-options {:optimizations :simple}}) ?

thheller16:05:46

if you want to do it via release options and not in the config itself use (shadow/release :build-id {:config-merge [{:compiler-options ...}]})

kenny16:05:59

Gotcha. Not a big deal. Was trying to figure out if it should go in it's own build step or just be added to the release step given it'd run fast.

thheller16:05:34

@kenny one setting that must be set is :compiler-options {:source-map true}

kenny16:05:38

Seems like a very useful tool though. Thanks! Will always output one as a build artifact. Great to compare build sizes after adding deps.

thheller16:05:45

so that would invalidate the cache since that isn't true by default for release builds

kenny16:05:07

When would it be useful to have that setting be true for release builds?

thheller16:05:19

if you want source maps 😉

kenny16:05:47

I guess you'd only want them in a release build for debuggery?

thheller16:05:30

that depends .. some people always use them with things like sentry or so

kenny16:05:12

Ah, that's a good idea.

lilactown16:05:43

hrm annoying. datascript isn’t working for me in advanced optimizations, but works in simple 😧

thheller17:05:08

datascript requires externs because its written incorrectly

kenny17:05:25

We use datascript in our released app and it works.

thheller17:05:53

I didn't look into why they are required but they are ...

lilactown17:05:27

very annoying. wish they had this in the manual.

lilactown17:05:03

do I need to create my own externs or can I just list there’s?

thheller17:05:27

well the externs are bundled

thheller17:05:35

just via :foreign-libs which shadow-cljs doesn't support

thheller17:05:50

just include :externs ["datascript/externs.js"] in your :compiler-options

lilactown17:05:28

that worked! thanks!

thheller17:05:05

or find out what is getting renamed and fix it 😉

lilactown17:05:16

maybe when I have free time 😂

kenny17:05:37

We use FontAwesome's React package in our app. After generating a build report, I see the icons deps take up nearly 30% of the build size. We explicitly import icons which supposedly allows tree shaking to work. I'm guessing that however FontAwesome expects tree shaking to work is not the same way it works in shadow-cljs? Is there way to make it work or no dice?

thheller17:05:13

I don't know the fontawesome package but if you require separate files it should work

thheller17:05:28

if you use :refer (That Icon) then that has no effect

thheller17:05:32

that'll always import all

kenny17:05:09

Is that the same as this?

(:require
  ["@fortawesome/free-solid-svg-icons" :as solid-icons])
solid-icons/faCircle

thheller17:05:20

that imports all

thheller17:05:54

["@fortawesome/free-solid-svg-icons" :as solid-icons] only that matters. there is no DCE for npm packages

thheller17:05:32

but all the icons are in that file so no luck

kenny17:05:43

Ah. Looks like FontAwesome expects you to use Webpack 2.

thheller17:05:01

that isn't supported

thheller17:05:15

can't support babel/webpack specific hacks

thheller17:05:02

oh actually that would work yes

thheller17:05:27

hmm actually I have no clue

thheller17:05:31

the file does exist

kenny17:05:44

To clarify, when I do this

(:require
  ["@fortawesome/free-solid-svg-icons" :as solid-icons])
it imports an index.js file. If I were to do this:
(:require
  ["@fortawesome/free-solid-svg-icons/faCoffee" :as fa-coffee])
it'd import faCoffee.js?

thheller17:05:23

["@fortawesome/free-solid-svg-icons/faCoffee.js" :as fa-coffee] also works if you want to be sure 😉

kenny17:05:38

And when I run a build, it will just throw the code (minified?) into the final JS file?

thheller17:05:05

it'll include just that file yes

thheller17:05:18

as long as you don't include the index anywhere else

thheller17:05:30

the index contains all icons

thheller17:05:38

the faCoffee.js only contains one icon

kenny17:05:14

Gotcha. Curious, given this library supports tree shaking, does that mean it'd be compatible with closure's tree shaking?

thheller17:05:35

well given how simple the lib is probably

thheller17:05:31

but webpack tree shaking and closure tree shaking are two very different things

thheller17:05:42

so I wouldn't hold my breath

kenny17:05:00

How are they different?

kenny17:05:54

They use the same terminology - "dead code elimination". A bit annoying how everything is so overloaded.

thheller17:05:04

if you figure it out let me know 😉

thheller17:05:33

the fundamental difference is that closure operates on one global scope

thheller17:05:41

so it can do things webpack can't do

thheller17:05:51

since webpack can't move stuff out of the scope they are declared in

kenny17:05:36

Oh I see. If I know that all the npm deps I use would be compatible with Closure, is there a way to enable it?

thheller17:05:36

I haven't tested this in a rather long time and wouldn't consider it supported at this time

thheller17:05:49

but if you are lucky 😉

kenny17:05:10

Ha. I'll try it for fun.

thheller17:05:49

you'll probably run into issues with react and react-dom

thheller17:05:55

last time I tried they required manual externs

kenny17:05:29

Oh, yeah - we definitely use those. I assumed it'd "just work" given how popular those are.

thheller17:05:53

they never worked without externs

thheller17:05:14

well .. I'm not actually sure ... it has been years sind I tried

thheller17:05:34

but unless they changed their builds they would probably still be required

kenny17:05:06

I get a bunch of new warnings when compiling 🙃

kenny17:05:24

for example:

------ WARNING #9 --------------------------------------------------------------
 File: node_modules/react-dom/cjs/react-dom.production.min.js:176:316
 unreachable code
--------------------------------------------------------------------------------

thheller17:05:59

I warned you 😉

kenny17:05:45

Yep - no worky 🙂

kenny17:05:22

Does anyone do crazy stuff like run webpack on their build?

thheller17:05:57

that would be crazy indeed

thheller17:05:13

especially if you expect the webpack tree shaking stuff to trigger since that will not

kenny17:05:52

Including the specific fontawesome js files does the trick :thumbsup::skin-tone-2:

thheller17:05:25

@wilkerlucio I saw the ticket regarding class. do you have an actual example where this fails? which class?

thheller17:05:51

gotta be careful with code on npm since its often babel rewritten code which has other semantics than ES6 has

wilkerlucio18:05:37

@thheller I was doing in browser, I'm loading strait from script tags, those using native ES6 classes, you can see the discussion I have around it yesterday: https://clojurians.slack.com/archives/C03S1L9DN/p1557803014008100, please let me know if you need more clarifications about it

thheller18:05:49

so the Rete.Control isn't an actual ES6 class if you used the npm version?

wilkerlucio18:05:30

@thheller I'm not sure, I wasn't able to use that loading from NPM (that issue we discussed on the polyfill)

thheller18:05:07

what did you use then?

thheller18:05:30

var Control =
/*#__PURE__*/
function () {
  function Control(key) {
    _classCallCheck(this, Control);

    _defineProperty(this, "key", void 0);

    _defineProperty(this, "data", {});

    _defineProperty(this, "parent", null);

    if (this.constructor === Control) throw new TypeError('Can not construct abstract class');
    if (!key) throw new Error('The key parameter is missing in super() of Control ');
    this.key = key;
  }

  _createClass(Control, [{
    key: "getNode",
    value: function getNode() {
      if (this.parent === null) throw new Error('Control isn\'t added to Node/Input');
      if (this.parent instanceof Node) return this.parent;
      if (!this.parent.node) throw new Error('Control hasn\'t be added to Input or Node');
      return this.parent.node;
    }
  }, {
    key: "getData",
    value: function getData(key) {
      return this.getNode().data[key];
    }
  }, {
    key: "putData",
    value: function putData(key, data) {
      this.getNode().data[key] = data;
    }
  }]);

  return Control;
}();

wilkerlucio18:05:39

<script src=""></script>
    <script src=""></script>
    <script src=""></script>

thheller18:05:41

this is the "class" in the npm package

thheller18:05:52

right yeah the min is the same there

thheller18:05:01

there is not a single use of class in that package

wilkerlucio18:05:28

interesting, still having the problem when trying to call the construct, maybe that generating the native class somehow?

thheller18:05:17

well things are a bit more complicated depending on what you are trying

thheller18:05:31

if you are trying the Reflect way with a rewritten class like that it won't work

thheller18:05:09

the rete package only contains babel-rewritten code

wilkerlucio18:05:18

the issue I'm having is how to extend it and call the parent constructor

wilkerlucio18:05:27

because its required by the api design

thheller18:05:36

even though the package contains a build/rete.esm.js file but thats still rewritten by babel and not ES6 code

wilkerlucio18:05:18

and their docs point to use of native classes, so I'm not sure whats going on inside of it

thheller18:05:20

yes I understand but if you are trying to do this with ES6 ways that won't work

thheller18:05:24

since its not an ES6 class

thheller18:05:51

they probably assume that you'll use babel which would rewrite the code in a compatible way?

wilkerlucio18:05:35

they provide docs for the .min usage as well, also suggesting usage of ES6 classeasa

thheller18:05:25

that might be but the code does NOT contain ANY es6 classes

wilkerlucio18:05:49

you have a guess why/how parent constructor calling is blocked?

thheller18:05:01

function _classCallCheck(instance, Constructor) {
  if (!(instance instanceof Constructor)) {
    throw new TypeError("Cannot call a class as a function");
  }
}

wilkerlucio18:05:33

so they polyfill the check

thheller18:05:38

thats the non minified version .. a bit more readable but the same code

thheller18:05:11

there is nothing ESM about it ... but lots of packages on npm pretend to be ESM when they are not

thheller18:05:29

well its ESM because of the import/export

thheller18:05:35

but not because of any other language features

wilkerlucio18:05:36

yeah, but seems like this is just mimics the ES6 behavior

thheller18:05:43

no it really doesn't

thheller18:05:09

well ... you need to adjust what you are trying

wilkerlucio18:05:12

I mean mimics in the sense it blocks direct calls to the constructor fn (using that validator)

thheller18:05:31

in your ticket you mention Reflect.setPrototypeOf(B.prototype, A.prototype) and stuff

thheller18:05:40

this will NOT work if you don't have an actual ES6 class

thheller18:05:41

and you don't (in the case of Rete)

wilkerlucio18:05:42

gotcha, but still that wasn't the main problem, sorry to insist in this point, but the real blocker to me is the parent constructor, fixing prototypes is easy, but thanks for pointing it, I'll improve the example there

thheller18:05:46

I'm not super sure how the babel-rewritten stuff expects inheritence to work

thheller18:05:05

yes I understand that you want to do that

thheller18:05:17

and that I fully agree that CLJS should support that

wilkerlucio18:05:23

is not that I want, its required by the lib, unless there is some way around that I'm missing

thheller18:05:26

but the issue here is not with actual ES6 classes

thheller18:05:50

function _inherits(subClass, superClass) {
  if (typeof superClass !== "function" && superClass !== null) {
    throw new TypeError("Super expression must either be null or a function");
  }

  subClass.prototype = Object.create(superClass && superClass.prototype, {
    constructor: {
      value: subClass,
      writable: true,
      configurable: true
    }
  });
  if (superClass) _setPrototypeOf(subClass, superClass);
}

thheller18:05:56

you probably need to mimic that

wilkerlucio18:05:54

thanks, I'll try that

thheller18:05:59

I can't find an actual example of how to use the rete stuff in your discussion in #cljs-dev

thheller18:05:12

only the code to construct the class but not where its actually used?

thheller18:05:19

how would you trigger the error?

wilkerlucio18:05:04

that's a bit far in the setup, in the construction of the editor, but you can replicate by simply trying to instantiate the class

wilkerlucio18:05:22

raw messy stuff, but this is my setup for init it:

wilkerlucio18:05:23

(fp/defsc ReteEditor
  [this {::keys []}]
  {:pre-merge         (fn [{:keys [current-normalized data-tree]}]
                        (merge {::editor-id (random-uuid)} current-normalized data-tree))
   :ident             [::editor-id ::editor-id]
   :query             [::editor-id]
   :componentDidMount (fn []
                        (go-catch
                          (let [container (gobj/get this "editorContainer")
                                editor    (js/Rete.NodeEditor. "[email protected]" container)
                                num-comp  (new NumComponent)
                                _         (do
                                            (.use editor js/ConnectionPlugin.default)
                                            (.use editor js/ReactRenderPlugin.default)
                                            (.register editor num-comp))
                                engine    (js/Rete.Engine. "[email protected]")
                                _         (.register engine num-comp)
                                n1        (<!p (.createNode num-comp #js {:num 3}))
                                n2        (<!p (.createNode num-comp #js {:num 5}))]
                            (.addNode editor n1)
                            (.addNode editor n2)
                            (.on editor "process nodecreated noderemoved connectioncreated connectionremoved"
                              (fn []
                                (js/console.log "EVENT")))

                            (.. editor -view resize)
                            (.trigger editor "process"))))
   :css               [[:.container {:width "500px"}]]}
  (dom/div :.container {:ref #(gobj/set this "editorContainer" %)}))

wilkerlucio18:05:47

(def NumControl
    (js-class
      {::extends     js/Rete.Control
       ::constructor (fn [emitter key readonly]
                       (let [this (js-this)]
                         (.call js/Rete.Control this key)
                         (gobj/set this "render" "react")
                         (gobj/set this "component" ReactNumControl)
                         (gobj/set this "props" {:emitter emitter :ikey key :readonly readonly})))}))

thheller18:05:40

I have no clue whats going on there 😛

wilkerlucio18:05:56

(defn js-class [{::keys [constructor] :as definition}]
  (let [c     (or constructor (fn []))
        proto (gobj/get c "prototype")]
    (doseq [[k v] (dissoc definition ::constructor)]
      (case k
        ::extends
        (goog/inherits c v)

        (gobj/set proto (name k) v)))
    c))

thheller18:05:07

thats not the part I'm looking for

thheller18:05:24

I know how to do that part ... I need Rete to use the class

wilkerlucio18:05:48

the use is in the Fulcro component, num-comp (new NumComponent)

thheller18:05:02

without fulcro

thheller18:05:06

preferably without react even

wilkerlucio18:05:49

that's not actually possible, hehe, rete depends on some rendering to create some parts of it, but you can ignore the react/fulcro part, its just one container element and using componentDidMount to start

wilkerlucio18:05:33

here you can see a full demo from Rete: https://codepen.io/Ni55aN/full/xzgQYq/

wilkerlucio18:05:43

I mostly copied from that

thheller19:05:24

@wilkerlucio

(defn NumComponent
  {:jsdoc ["@constructor"]}
  []
  (this-as this
    (.call (js/Object.getPrototypeOf NumComponent) this "Number")
    this))

(set! NumComponent -prototype
  (js/Object.create r/Component.prototype
    #js {:constructor
         #js {:value NumComponent
              :writeable true
              :configurable true}

         :builder
         #js {:value
              (fn [node]
                (this-as this
                  ;; do stuff
                  ))}

         :worker
         #js {:value
              (fn [node inputs outputs]
                ;; do stuff
                )}}))

(js/Object.setPrototypeOf NumComponent r/Component)

thheller19:05:33

with

["regenerator-runtime/runtime"]
    ["rete" :as r]

thheller19:05:02

no clue if it actually works .. can't untangle this OOP crazyness 😛

thheller19:05:00

but new works and the .name seems to get assigned properly

wilkerlucio19:05:05

@thheller maybe something is wrong, I got Uncaught TypeError: Object.getPrototypeOf(...).call is not a function

wilkerlucio19:05:20

running new ns.NumComponent() on the console

wilkerlucio19:05:29

ok, I fixed that line, swiped with: (.call (gobj/get (js/Object.getPrototypeOf NumComponent) "constructor") this "Number")

wilkerlucio19:05:33

now it works! 🙂

wilkerlucio19:05:02

thanks for looking it up, really helpful

wilkerlucio19:05:56

but there is something about that puzzling me, I don't really understand how (.call (gobj/get (js/Object.getPrototypeOf NumComponent) "constructor") this "Number") works, the way I'm seeing it, the constructor in NumComponent is a js value, which contains a value to NumComponent, how does that line figures the parent constructor and call it? its some JS magic going on inside?

thheller19:05:52

I just took what the babel stuff does and didn't question it 😉

neupsh20:05:28

I want to write a small library for myself in cljc where I expose apis that work for both clojure and clojurescript. Some of the implementations for these apis will use java/clojure external libraries and npm libraries using reader conditionals so that I can and export it as jar files and use them in both clojure and clojurescript world. Is there a way to achieve this with a shadow-cljs? Is there any template for such kind of library projects?

thheller20:05:58

shadow-cljs currently does not support publishing libraries

thheller20:05:07

you can just use a simple project.clj and use lein though

lilactown22:05:53

alright, back to my chrome extension after awhile. I think I ran into this before, but I’m currently getting: [chromex] an error occurred during the call to chromex.ext.tabs/execute-script: Could not load file 'out/content-script.js' for content script. It isn't UTF-8 encoded.

chadharrington22:05:17

I am a first-time shadow-cljs user. In trying it out today, I hit an INTERNAL COMPILER ERROR 🙁 I created a minimal reproduction in this repository: https://github.com/Dept24c/viz-min The README has instructions on how to reproduce the error. Can anyone help me with this?

thheller22:05:04

@chad.harrington please include the full error you get

chadharrington22:05:18

It's pretty big, but it starts with: `[:app] Compiling ... [:app] Build failure: failed to convert sources {:tag :shadow.build.closure/convert-error, :sources [[:shadow.build.npm/empty "shadow$empty.js"] [:shadow.build.npm/resource "node_modules/base64-js/index.js"] [:shadow.build.npm/resource "node_modules/ieee754/index.js"] [:shadow.build.npm/resource "node_modules/isarray/index.js"] [:shadow.build.npm/resource "node_modules/buffer/index.js"] [:shadow.build.npm/resource "node_modules/viz_DOT_js/full.render.js"]]} ExceptionInfo: failed to convert sources shadow.build.closure/convert-sources-simple*/fn--14326 (closure.clj:1809) shadow.build.closure/convert-sources-simple* (closure.clj:1803) shadow.build.closure/convert-sources-simple* (closure.clj:1684) shadow.build.closure/convert-sources-simple (closure.clj:1960) shadow.build.closure/convert-sources-simple (closure.clj:1912) shadow.build.compiler/maybe-closure-convert (compiler.clj:1016) shadow.build.compiler/maybe-closure-convert (compiler.clj:1009) shadow.build.compiler/compile-all (compiler.clj:1267) shadow.build.compiler/co mpile-all (compiler.clj:1128) shadow.build.api/compile-sources (api.clj:256) shadow.build.api/compile-sources (api.clj:248) shadow.build/compile (build.clj:377) shadow.build/compile (build.clj:368) shadow.cljs.devtools.server.worker.impl/build-compile (impl.clj:304) shadow.cljs.devtools.server.worker.impl/build-compile (impl.clj:290) shadow.cljs.devtools.server.worker.impl/do-resource-update (impl.clj:887) shadow.cljs.devtools.server.worker.impl/do-resource-update (impl.clj:850) shadow.cljs.devtools.server.util/server-thread/fn--16766/fn--16767/fn--16775 (util.clj:304) shadow.cljs.devtools.server.util/server-thread/fn--16766/fn--16767 (util.clj:303) shadow.cljs.devtools.server.util/server-thread/fn--16766 (util.clj:276) java.lang.Thread.run (Thread.java:748) Caused by: RuntimeException: INTERNAL COMPILER ERROR. Please report this problem. An enclosing scope is required for change reports but node LABEL 13 [length: 2] [source_file: node_modules/viz_DOT_js/full.render.js] doesn't have one. Node(F OR): node_modules/viz_DOT_js/full.render.js:13:4095 function Rv(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0,j=0,k=0;f=a;while(1){j=c[f>>2]|0;if(!j){k=6;break}if((c[j>>2]|0)==(b|0))b...`

thheller22:05:22

yeah its a closure compiler issue as expected. too tired to look into it now. headed to bed.

lilactown22:05:01

my guess is the clojure compiler sees an empty (:require) in your ns form

thheller22:05:24

@lilactown dunno what that means. it should be utf-8

thheller22:05:40

INTERNAL COMPILER ERROR typically is a closure ocmpiler issue

lilactown22:05:48

@thheller my googling says I should set the :closure-output-charset to "US-ASCII"

lilactown22:05:05

I tried that but it’s still not working. let me try cleaning things out