Fork me on GitHub
#shadow-cljs
<
2020-10-02
>
Karol Wójcik09:10:42

Is it possible to include dependency only on nodejs? Something like (:require-node)?

Aron10:10:18

I am a bit confused with the missing runtime error. I have a node-test build that I ran with node, but that doesn't yield a runtime, or at least not one I could yet connect to.

jcf11:10:49

Hello all! I'm working on a little prototype web app built on top of AWS Amplify, and I've hit an interesting problem when applying advanced optimisations. Amplify generates code for you that defines the attributes of models that can be found in your GraphQL backend. In my case the generated models/index.js file contains this:

// @ts-check
import { initSchema } from '@aws-amplify/datastore';
import { schema } from './schema';



const { Product, ListedProduct, List } = initSchema(schema);

export {
  Product,
  ListedProduct,
  List
};
The schema file is a JavaScript file with lots of data…
export const schema = {
    "models": {
        "Product": {
In development I can require these models from Clojurescript with (:require ["../models/index" :as model]) , and things like model/Product work just fine. In production, with advanced compilation, the value of model/Product is undefined. In fact, all three of the models I'm playing with are undefined.
(js/console.log "Models:" #js {:List          model/List
                                 :ListedProduct model/ListedProduct
                                 :Product       model/Product})
That logs this in Firefox:
Models: 
{…}

List: undefined

ListedProduct: undefined

Product: undefined

<prototype>: Object { … }
grocer.cljs:272:48

jcf11:10:24

I'm fairly sure this is some dead code elimination/var renaming taking place during advance compilation.

jcf11:10:16

I initially expected some property was being renamed, which is why Amplify wouldn't initialise the DataStore it provides, but given these vars resolve to nothing…

thheller12:10:55

yeah closure will rename this code. you can either create externs or access the names by string

thheller12:10:09

is quick too though

thheller12:10:25

could maybe even generate that automatically somehow

jcf12:10:38

Wouldn't model/Product get renamed consistently though?

jcf12:10:52

I'm using js-interop in places, and I looked at adding simple externs.

thheller12:10:53

no because the JS file uses "Product" (as in a String)

jcf12:10:57

So I can't do something like this:

(ns foo
  (:require ["../models" :as models]))

(.subscribe DataStore models/Product)

jcf12:10:25

I'd need to do (.subscribe DataStore (j/get-in models :Product))?

thheller12:10:51

with the simple externs you can do models/Product

jcf12:10:21

In externs/<build>.txt I need to add something like this?

# Fix Amplify's models being undefined :)
models/Product

thheller12:10:12

just Product

jcf12:10:35

Awesome. I'll echo ... into a file and mint a release build now. 👍

jcf12:10:31

@U05224H0W I love you! That did it. 💥

jcf12:10:39

Thank you so much!

👍 3
thheller12:10:13

@ashnur node-test does not support a REPL. just use node-repl instead.

Aron14:10:25

there is no such target as node-repl

Aron14:10:38

I am even more confused now 🙂

Aron14:10:04

thanks, I found this, but I am not yet sure how to use it for the purpose I need the repl

dpsutton14:10:10

that will start a repl, right? then you can develop and require your code as desired

Aron14:10:18

i wish it were as simple

Aron14:10:13

I need to somehow connect it to my editor, right? because "no one actually types in the repl, who would do that" I saw this on twitter. And copy pasting lots of stuff is difficult anyway

dpsutton14:10:08

yeah most likely. CIDER can do this. what's your editor?

Aron14:10:18

neovim/conjure

dpsutton14:10:33

i think if you put the nrepl options in the shadow config it will start up with that stuff and you should be able to connect as normal

Aron14:10:44

I usually have to do a ConjureConnect to the nrepl port and then ConjureShadowSelect to select the build/namespace I am connecting to. But this second part doesn't work

Aron14:10:29

If I write ConjureShadowSelect it tells me that the watch for the build is not running. Which is not true, it's running, but it's a node-test build.

Aron14:10:11

So, just to be clear, I don't think either tool is wrong in any way, I just don't know what I don't know that would connect it.

thheller14:10:20

@ashnur I don't have a clue about the conjure parts. shadow-cljs node-repl will launch it as will (shadow.cljs.devtools.api/node-repl) (from CLJ)

thheller14:10:41

if ConjureShadowSelect asks for a build id that would be :node-repl (but it needs to be started elsewhere first

Aron14:10:29

But what port?

thheller14:10:58

the usual nrepl port

thheller14:10:53

maybe there is an option in conjure to start the node-repl directly. I don't know.

Aron14:10:50

the usual is already used by the actual build of the application running

Aron14:10:12

ok, I started the node repl, and tried to connect to 3334 port which seem to work, but if I try to evaluate the buffer, it just throws errors

thheller14:10:57

you need to do the select thingy

thheller14:10:02

otherwise you are just in a clojure REPL

Aron14:10:51

right, sorry, I did do that. I selected :node-repl as you said. The evaluation certainly works, I think I have a new problem now, not related to either conjure or shadow. Thanks

Olical15:10:09

You may also want to use node-repl, not :node-repl when selecting

scottlowe16:10:33

I'm using an js-joda via an npm module and my target is :browser. Unfortunately the js-joda code contains calls to the ES2016 feature .includes function (on Array) instead of indexOf which fails in IE11. I've tried all sorts of shadow-cljs config combinations wtihout any luck, e.g. :js-options {:babel-preset-config {:targets {:ie 11}} or :compiler-options {:rewrite-polyfills true} which I believe only writes polyfills for ES6+ anyway.

scottlowe16:10:34

Has anybody managed to configure shadow-cljs such that an ES2016 feature is re-written or polyfilled for ES5 compatibility?

thheller16:10:48

the output is supposed to be es5 assuming you didn't override :output-feature-set

thheller16:10:00

but maybe it doesn't detect the .includes properly

thheller16:10:45

there is :compiler-options {:force-library-injection #{"polyfill-name"}}

thheller16:10:50

don't know the includes name though

thheller16:10:07

or just add the polyfill via external lib like https://polyfill.io/v3/

scottlowe16:10:29

Thanks, both of you. I believe I've tried the correct :output-feature-set and other config options already, but I'll double check. Just to confirm, I don't need the babel-preset-config at all?

scottlowe16:10:27

I will probably fallback to adding the polyfill manually, I was just convinced that shadow-cljs would take care of it and found that idea attractive. Anyway, let me go away and check my config again. Perhaps some of the config options I've got in there are interfering with each other. Thanks

scottlowe16:10:17

Hmm... no, I can't get it to work. Perhaps the includes call isn't being detected properly, as you say. For completeness, the offending lines in the third-party code are chained calls, so perhaps that makes it harder to detect https://github.com/js-joda/js-joda/blob/a1a635a7e4e506dfa7a9eedcc932571bdba9c1b2/packages/locale/src/format/cldr/CldrDateTimeTextProvider.js#L226

scottlowe16:10:36

Anyway, I will simply include the polyfills via that :force-library-injection config key for now. Thanks!

scottlowe16:10:47

That worked 🙂 I also uncovered a call to Object.values. The final shadow-cljs config was :compiler-options {:force-library-injection ["es6/array/includes" "es6/object/values"]}

👍 3