Fork me on GitHub
#shadow-cljs
<
2021-02-10
>
bringe02:02:06

Hello. I'm trying to require js in the same project, compiled from typescript, following this guide: https://shadow-cljs.github.io/docs/UsersGuide.html#_requiring_js, but I can't seem to get it to work. I have a state.ts file that's compiled to out/state.js - I added out to the shadow-cljs source-paths, since I read that js requires are read from the classpath, then I tried to require it in the ns form like (:require ["out/state" :as state] ... but it just appears to be an empty object :thinking_face:. This js file has exports and is used elsewhere in typescript files in the project.

bringe02:02:55

It does build though via shadow and I don't get any errors - if I rename state in the path to something like statee that doesn't exist I see this error printed: JS reload failed Error: Cannot find module 'out/statee' so it appears that it at least sees the module state since I don't get an error with that.

bringe02:02:41

Ok now seeing the error: Cannot find module 'out/state' so maybe it's not found. Hoping/guessing I'm just missing some small detail about this process.

johnjelinek05:02:17

> node ./main.js
file:///home/john/cdktfclj/main.js:5
var SHADOW_IMPORT_PATH = __dirname + '/.shadow-cljs/builds/cdktf/dev/out/cljs-runtime';
                         ^

ReferenceError: __dirname is not defined
    at file:///home/john/cdktfclj/main.js:5:26
    at file:///home/john/cdktfclj/main.js:1789:3
    at ModuleJob.run (internal/modules/esm/module_job.js:152:23)
    at async Loader.import (internal/modules/esm/loader.js:166:24)
    at async Object.loadESM (internal/process/esm_loader.js:68:5)
I'm getting this error with the code that comes out of shadow-cljs compile app

johnjelinek05:02:35

looks to be related to "type": "module", inside my package.json

johnjelinek05:02:02

hmm ... it looks kinda like shadow-cljs is maybe outputting AMD instead of CommonJS -- is this configurable?

thheller08:02:09

AMD/CommonJS is pretty much the same so that doesn't matter

thheller08:02:56

and no this is not configurable. there is an experimental :target :esm but you shouldn't use this when building for node currently

johnjelinek15:02:26

I didn't think CommonJS did an IIFE like AMD did

thheller15:02:23

it doesn't have to but it makes no difference. it is not the cause of your issue and would not affect anything. __dirname not being present is purely an effect of node loading the file as a ESM module

johnjelinek15:02:34

you're right -- the __dirname problem went away when I removed the --experimental flag to node

johnjelinek15:02:51

"type": "module" is the same as --experimental

thheller15:02:03

why do you have that in the first place?

johnjelinek16:02:34

because I need to interop with typescript and when I generate it as CommonJS instead of ES2015 then I get the error at the top of the other thread: module$docker$index is not defined

thheller16:02:38

if you make a reproducible example I can take a look but so far I'm just guessing

johnjelinek20:02:43

sure, I can do that

thheller08:02:56

@brandon.ringe I tried to explain this in the guide but I will try again. the PATH you require MUST be on the classpath and MUST be an actual path. ["out/state" ...] will look for node_modules/out since it doesn't start with / or ./. so instead use ["/state.js" :as state]. the classpath will then be searched in order and if you have out on the classpath it'll eventually find <project>/out/state.js

bringe18:02:39

Thanks for explaining more. I've managed to get to a new error with that. I have out on the classpath (have verified with shadow-cljs classpath), and state.js exists in out, along with other js files and directories containing js files. When I try to require the file with ["/state.js" :as state] I get the following error:

[:calva-lib] Build failure:
FileNotFoundException: /home/brandon/development/calva/out/doc-mirror (Is a directory)
        java.io.FileInputStream.open0 (FileInputStream.java:-2)
        java.io.FileInputStream.open (FileInputStream.java:195)
        java.io.FileInputStream.<init> (FileInputStream.java:138)
        shadow.build.data/sha1-file (data.clj:341)
        ...

bringe18:02:25

It's true that doc-mirror is a directory, but I don't see how that is relevant / why it matters :thinking_face:

bringe18:02:52

That directory does contain an index.js file (along with others), but it's the first one to contain one, alphabetically. Not sure if that has anything to do with the error.

thheller22:02:26

then use /doc-mirror/index.js. it doesn't do any of the npm nonsense of guessing which file you mean. just refer to the file by name.

bringe22:02:07

Sorry if I wasn't clear. I don't want to import that file. I want to import /state.js which is in the out directory. out is on the classpath, the file is in out and I import it at "/state.js" :as state . So I'm referring to it by name and starting with / so it doesn't check node_modules. When I try to do that, I get that error about that unrelated directory.

bringe22:02:08

I can make an issue with a repro case if you think that would help.

aratare12:02:29

Hi there @thheller. Sorry for pinging you directly but I feel this is something only you can fix. So I'm working on a fulcro project with Elastic UI and stumbled across this error Uncaught (in promise) Module not provided: ./assets/plus.js when trying to use a React component from the UI library. But this component works perfectly find in a normal JS library, in fact I was testing around with CodePen and there's nothing wrong with it. So I suspect it has something to do with shadow-cljs. I've created a GH issue with more details here: https://github.com/thheller/shadow-cljs/issues/840. Thanks in advance 🙂

thheller12:02:43

answered on github

🙏 3
Alexis Vincent13:02:37

@thheller Are the goog.provide lines generated by shadow or by cljs compiler?

Alexis Vincent13:02:38

And is there a reason that it’s important that throw new Error('Namespace "' + name + '" already declared.'); be thrown from within goog.provide declaration? I’m trying to get webpack to happily hot reload cljs generated with :npm-module

thheller14:02:50

@mail024 why do you want to let webpack do that instead of shadow-cljs?

Alexis Vincent14:02:11

I’m experimenting with cljs/nextjs interop

Alexis Vincent14:02:44

So I want the repl connection, but to leave everything else up to the rest of the toolchain.

Alexis Vincent14:02:08

module loading; optimisation; HMR; etc

thheller14:02:01

been a while since I looked at webpack HMR but it used to have issues with reloading cljs code

thheller14:02:18

the exception you can get rid of by deplacing goog.provide with goog.constructNamespace_ as done here https://github.com/thheller/shadow-cljs/blob/f28003cbb062fd27685048e8b4793eb05ca8f829/src/main/shadow/cljs/devtools/client/env.cljs#L145

thheller14:02:15

if you are experimenting with interop stuff you should really use :target :esm instead

Alexis Vincent14:02:31

thanks! I actually just made a patch goog that does just that. Yours is simpler though

thheller14:02:34

:npm-module has all sorts of little quirks that'll really get in your way

Alexis Vincent14:02:55

ok thanks. I’ll check that out

Alexis Vincent14:02:17

Been running through the clojurescript codebase to try get a better idea of how everything works. My experience with cljs thus far has largely been via shadow-cljs so I’m not that familiar with standard cljs emmission.

Alexis Vincent15:02:44

yeah, I worked through that a few months back. Ultimately I decided to write something native clojurescript. But I’m experimenting again with interop. Want to try see if I can get a clean interop story with native js tooling

Alexis Vincent15:02:21

Do you know if the emmitter is the only place that cares about google closure? Does it feed in higher up?

thheller15:02:24

what do you mean by "cares about google closure"?

Alexis Vincent15:02:58

If I were to swap out the cljs emmitter and replace it with something that doesn’t output in a google closure friendly way, how much would I need to change up in the analyser say

thheller15:02:39

about everything

thheller15:02:09

I have been thinking about writing a cljs compiler variant that emits pure modern ESM code with no traces of closure

thheller15:02:29

because I think this really cannot be retrofitted into the current compiler

thheller15:02:35

but yeah its a massive amount of work

Alexis Vincent15:02:32

Would love to talk to you about this. It’s something I want to see and would be prepared to support. financially or otherwise

thheller15:02:40

it might be possible but I'm already working around too many issues with shadow-cljs that this is not an avenue I wanted to pursue

thheller15:02:42

its mostly a time issue for me. the final "gain" is questionable since things like the REPL and hot-reload will get much harder

thheller15:02:08

the only downside of the current way really is that JS tools don't like it but otherwise its pretty nice

thheller15:02:33

I mean you can always do the hacks that :target :esm or :npm-module do and that works ok enough for a bit

thheller15:02:45

but to do it cleanly things need to be really different

Alexis Vincent15:02:06

I think the downside of JS not liking it actually is everything for me

thheller15:02:59

yeah getting smoother JS interop would be useful for a lot of tools