Fork me on GitHub
#clojurescript
<
2018-02-08
>
caleb.macdonaldblack07:02:32

:closure-defines {
    goog.DEBUG              false
    goog.WP_SERVER_URI "I PROMISE I WORK"}
This is being ignored in my clojurescript re-frame project. Any ideas? Doesn’t work with figwheel or a :whitespace compile

joelsanchez08:02:10

that's not the way to use the feature, in your project.clj you do this:

:closure-defines {
  my.app/one "A value"
  my.app/two "Another one"}
then in "my.app":
(goog-define one "Default value one")
(goog-define two "Default value two")

rauh08:02:13

@caleb.macdonaldblack Whitespace won't take closure defines. It's also noted in the docs IIRC

thheller08:02:59

or use shadow-cljs where they just work 😉

chrisblom11:02:01

has anyone used posh? (https://github.com/mpdairy/posh) What are your opinions?

kingmob15:02:34

Will Clojurescript attempt to read/use/analyse stuff in node_modules, even if you’re not using :npm-deps? I get some serious errors just trying to use package.json and node_modules for storage. I have a .js under node_modules that I added via :foreign-libs, but when compiling, it was still accessing (and erroring on) other files of that package.

kingmob15:02:11

In order to get it to work, I have to copy that same .js file out from node_modules, use the new location, and delete the package from node_modules and package.json entirely

juhoteperi15:02:10

@kingmob Yes, if node_modules exists, it will be used

kingmob15:02:24

I’m kind of surprised it’s looking at node_modules packages with npm-deps off, though

kingmob15:02:38

Is that documented anywhere?

juhoteperi15:02:00

:npm-deps is only about automatically installing Node modules, it is not related to being able to use libraries from node_modules

kingmob15:02:17

Hmm. This forces us to only use node_modules for packages that can be safely added (e.g., easily understood module formats). But there’s a zillion packages in npm, many of which aren’t nicely modularized (especially old shims we use), and this means we can’t use npm as an organizational tool.

juhoteperi15:02:32

It is possible this is not documented anywhere, the implementation was probably changed after the blogpost about npm-deps was written

kingmob15:02:23

I really thought npm-deps had to be on to enable this. I know cljs adds its own @cljs-oss/module-deps dependency to package.json, but I thought that was it.

juhoteperi15:02:59

There are probably four different use cases we should support: 1. Project has :npm-deps and :install-deps true 2. Project uses libraries with :npm-deps and uses :install-deps true 3. Project has package.json and packages are installed by manually running npm install and Node packages should be usable from Cljs 4. Project has Node packages installed but node_modules shouldn't be used Fourth one is currently broken. Maybe this could be fixed by adding third option (`:analyze-npm-deps` or something) which would be automatically enabled by :npm-deps or :install-deps, then only usecase 3. would need the option, and 4. would work. Or we default the option true and 4. can disable the option.

dnolen16:02:15

@juhoteperi or :npm-deps could optionally be false

dnolen16:02:22

instead of adding another option

juhoteperi16:02:37

Yes, that would work also. I'm not sure if making option take two different kinds of values (are there other options which work like this?) is much better than adding new option.

juhoteperi16:02:54

Hm, :warnings can be a boolean or map. Would make sense then.

dnolen16:02:32

there’s a few options that work this way and I don’t really see a problem with it

dnolen16:02:08

this seems like a very simple patch no?

dnolen16:02:34

for some reason I thought 4) was already handled, but I guess not

kingmob17:02:19

@juhoteperi @dnolen FWIW, my initial impression was that npm-deps meant “import these packages from node_modules for me automatically” and install-deps meant “also npm install them for me”. I assumed #4 was the case for anything not specified in either npm-deps or manually referred to in foreign-libs

juhoteperi17:02:54

@dnolen Yes, should be simple. I created issue about this (https://dev.clojure.org/jira/browse/CLJS-2494).

kingmob17:02:32

Does the undocumented :node-modules flag (https://dev.clojure.org/jira/browse/CLJS-2245) affect any of this? Or is that just about being able to use Yarn?

juhoteperi17:02:19

@kingmob That option doesn't exists, I think that was renamed to :install-deps

kingmob17:02:25

As someone who has to occasionally deal with older libs/shims, I’d personally vote for not having the default be auto-processing node_modules, at least not without the ability to exclude packages from processing. E.g., just this morning I added a project that, despite using CommonJS modules, triggered a bug in Closure compiler that caused it to die. The bug is fixed in recent versions, but for now, I have to abandon using npm for the package, and copy out the .min.js

kingmob17:02:28

I just worry that for a long time to come, there will frequently be something interfering with wholesale processing of node_modules

kingmob17:02:37

Just my $.02

gganley17:02:20

Hey folks I have been looking into CLJS for a very strange purpose. The OmniGroup (http://omnigroup.com) is introducing automation into their apps using Javascrip for Automation (JXA). Basically a replacement for applescript. I’m trying to find out if its possible to use CLJS as a replacement/DSL for JXA. https://omni-automation.com

kingmob18:02:16

@gganley Right off the bat, it seems like it should be possible, though there may be little issues involving config and libs

mfikes20:02:07

@gganley The stuff in this small repo might be useful https://github.com/blackgate/cljs-jxa-starter

gganley20:02:56

I think my goal is a bit different. Basically I want to write CLJS that is compiled into JS, then send it using a URL Scheme to OmniOutliner or OmniGraffle

gganley20:02:15

I’ll dig into it a bit more when I have the time and hopefully be able to explain it a bit better

Garrett Hopper21:02:32

I'm writing clojurescript aws lambda (nodejs) functions. I'd like to be able to use core.async, but I can't figure out how to make my handler function not immediately return my go block before the handler's callback function has been called.

justinlee21:02:47

if i understand what you’re asking @ghopper, I think it’s working as expected. go blocks return a channel which the calling function has to wait on. they kind of infect your code (kind of like async/await does in javascript or any function that returns a promise).

Garrett Hopper21:02:19

Yeah, I've figured out what it's doing. I'm wondering how I can prevent the handler function from returning early before the callback has been called. Once the handler returns the channel, aws lambda kills the function with an error.

Garrett Hopper21:02:38

Do I need some sort of node await/block library?

justinlee21:02:04

i haven’t messed with lambda, but how would you deal with asynchronous javascript code?

justinlee21:02:54

often there is some sort of “done” callback with these kinds of systems

Garrett Hopper21:02:15

I'm using some node http stuff; I pass it a callback which pushes onto a channel. The problem is once that stack reaches the top handler, there's not way for me to synchronously wait for the last return.

Garrett Hopper21:02:34

I guess I could have some sort of endless loop in the handler, but that doesn't feel quite right.

Garrett Hopper21:02:55

Can I have a blocking take in javascript?

chris21:02:30

not if you want your program to ever finish

chris21:02:49

you probably want a parking take

Garrett Hopper21:02:55

But will other async stuff continue to run if I do?

Garrett Hopper21:02:07

I don't want it to finish, I just want my callback to be called.

chris21:02:17

if you block the thread that's it

Garrett Hopper21:02:31

Yeah, that's what I thought.

chris21:02:33

if you park it, other stuff can happen

chris21:02:51

so if you block a js runtime it'll be deadlocked forever

Garrett Hopper21:02:52

I can't park and wait for my function return though.

chris_johnson21:02:59

Sorry, my bad for a drive-by answer while doing >1 other things at the same time - I do think you probably want to do your handling inside that callback to stop the runtime from calling the “default” callback for you, though

justinlee21:02:16

I think you’re going to want a (go (let [result (<! channel-returning-function)] (callback result))

chris_johnson21:02:22

but “blocking take” is not the right name for the thing I meant

justinlee21:02:37

as far as I can tell aws lambda waits for you to call that callback

Garrett Hopper21:02:51

@lee.justin.m The problem is that returns a channel, which then kills the whole thing.

Garrett Hopper21:02:59

It doesn't 😕

Garrett Hopper21:02:09

It wants the callback to be called before a return.

justinlee21:02:27

that doesn’t make any sense. you could never do anything async if that was true (?)

chris_johnson21:02:54

note that you will for sure actually want (callback nil result) if you call callback at all, since > AWS Lambda treats any non-null value for the error parameter as a handled exception.

Garrett Hopper21:02:04

That's what I thought... I'm not sure what it's doing exactly, but I know it works if I do normal callbacks, but with a core.async channel, it doesn't.

Garrett Hopper21:02:01

@chris_johnson Thanks, I am calling it with my result as the second argument.

chris_johnson21:02:14

See, I was proposing something more like (callback nil (go (<! channel-returning-fn))) but reading it now, I’m pretty sure that will just return the JSON.stringifyd representation of the channel

chris_johnson21:02:21

which is likely Not Helpful

Garrett Hopper21:02:56

Yeah, I've been trying (go (callback nil (<! channel-returning-fn))).

Garrett Hopper21:02:34

How would I create an endless loop that allows async stuff to continue running?

Garrett Hopper21:02:15

That just returns a channel immediately, no?

Garrett Hopper21:02:05

Huh, I might be an idiot...

(defn ^:export handler [event context callback]
  (when callback
    (go (callback nil (clj->js {:statusCode 200
                                :headers {}
                                :body (<! (go
                                            (<! (timeout 1000))
                                            "body")) })))))
Seems to work

Ryan Radomski21:02:10

Inside of the go loop you can continuously pull off of a channel endlessly. The channel that it returns allows you to manage that lifecycle

Garrett Hopper21:02:38

Nevermind, I don't think what I thought was happening is happening.

justinlee21:02:04

you aren’t waiting

justinlee21:02:18

I think the problem is that the go block doesn’t traverse function boundaries. so it doesn’t traverse clj->js

Garrett Hopper22:02:46

Anecdotally the function definitely seems to wait the specified amount of time, and it returns the correct body.

justinlee22:02:43

does this work

(defn ^:export handler [event context callback]
  (when callback
    (go (let [result (go (<! (timeout 1000)))]
          (callback nil (clj->js {:statusCode 200
                                  :headers {}
                                  :body "body"}))))))

joelsanchez22:02:45

sorry but...what were you trying? I don't seem to get it...

joelsanchez22:02:25

can't you just

(defn ^:export handler [event context callback]
  (when callback
    (go
      (<! (timeout 1000))
      (callback nil (clj->js {:statusCode 200
                              :headers {}
                              :body "body"})))))

justinlee22:02:15

right i think it need to be like that because the way you had it before, the outer go block cannot “see” past the clj->js function invocation so it doesn’t park and returns immediately

Garrett Hopper22:02:01

@lee.justin.m I'm trying yours now. It seems to park and wait even within clj->js. The function waits the 5 seconds I told it to wait, and it returns the correct body. (not some json channel representation)

Garrett Hopper22:02:06

Huh, your let/result function works exactly the same. I didn't think it would, since the result wasn't being used. I guess I don't entirely understand what the go macro does.

joelsanchez22:02:39

what does callback look like?

justinlee22:02:50

callback is part of the aws api

joelsanchez22:02:03

and does it return a value? a channel? or other thing?

Garrett Hopper22:02:16

@joelsanchez I suppose yours would work as expected to. Another case of me not understanding how go works.

Garrett Hopper22:02:29

Yeah, I don't have access to callback.

joelsanchez22:02:48

ok but what does it return? did you try (type (callback nil ...)) to know?

Garrett Hopper22:02:01

Once callback is called, the function is killed.

justinlee22:02:39

i’m pretty sure that this is what’s going on: aws waits for the javascript even loop to drain before killing your function and calling the default callback handler

justinlee22:02:02

if you don’t set up your go blocks correctly, they won’t park, and they’ll finish immediately

Garrett Hopper22:02:08

Huh, that'd make sense. I believe the issue was that I had a go block wrapping the whole http request function, but I was using parking-gets inside node api callbacks.

joelsanchez22:02:20

if the caller of handler does not <! its result, there's no way to block: handler will always return immediately

justinlee22:02:46

but that’s not a problem because that’s how aws works anyway: it waits for the event loop to drain

justinlee22:02:34

the problem is that if you don’t have the go blocks set up, it will just finish and not have anything waiting

Garrett Hopper22:02:37

@joelsanchez Yeah, the issue isn't actually handler returning immediately as I thought. I like @lee.justin.m's theory of the event stack draining.

justinlee22:02:09

“When the callback is called, the Lambda function exits only after the Node.js event loop is empty (the Node.js event loop is not the same as the event that was passed as a parameter).”

Garrett Hopper22:02:27

Where'd you find that?

justinlee22:02:27

^ I assume it waits for the event loop to drain even when you don’t call the callback handler

justinlee22:02:28

@ghopper for what it is worth, I don’t know what go blocks are doing either. state machine something something 🙂