shadow-cljs

https://github.com/thheller/shadow-cljs | https://github.com/sponsors/thheller | https://www.patreon.com/thheller
bringe 2021-02-10T02:06:06.121100Z

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.

bringe 2021-02-10T02:08:55.122400Z

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.

bringe 2021-02-10T02:15:41.123700Z

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.

johnjelinek 2021-02-10T05:13:17.124600Z

> 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

thheller 2021-02-10T08:59:09.128500Z

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

thheller 2021-02-10T08:59:56.128700Z

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

johnjelinek 2021-02-10T15:06:26.143800Z

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

thheller 2021-02-10T15:11:23.144Z

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

johnjelinek 2021-02-10T15:16:34.144200Z

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

johnjelinek 2021-02-10T15:16:51.144400Z

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

thheller 2021-02-10T15:19:03.144700Z

why do you have that in the first place?

johnjelinek 2021-02-10T16:23:34.158500Z

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

thheller 2021-02-10T16:59:38.158700Z

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

johnjelinek 2021-02-10T20:43:43.159700Z

sure, I can do that

johnjelinek 2021-02-10T05:16:35.124700Z

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

johnjelinek 2021-02-10T05:36:02.125900Z

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

thheller 2021-02-10T08:57:56.128400Z

@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

aratare 2021-02-10T12:02:29.132900Z

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 🙂

thheller 2021-02-10T12:40:43.133400Z

answered on github

🙏 1
Alexis Vincent 2021-02-10T13:19:37.134300Z

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

Alexis Vincent 2021-02-10T13:29:38.136600Z

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

thheller 2021-02-10T14:53:50.137Z

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

Alexis Vincent 2021-02-10T14:54:11.137300Z

I’m experimenting with cljs/nextjs interop

Alexis Vincent 2021-02-10T14:54:44.137900Z

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

Alexis Vincent 2021-02-10T14:55:08.138500Z

module loading; optimisation; HMR; etc

thheller 2021-02-10T14:56:01.139300Z

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

thheller 2021-02-10T14:56:18.139800Z

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

thheller 2021-02-10T14:57:15.140700Z

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

Alexis Vincent 2021-02-10T14:57:31.141300Z

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

thheller 2021-02-10T14:57:34.141500Z

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

Alexis Vincent 2021-02-10T14:57:55.141800Z

ok thanks. I’ll check that out

Alexis Vincent 2021-02-10T14:59:17.143300Z

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 Vincent 2021-02-10T15:19:30.145200Z

Thanks!

thheller 2021-02-10T15:24:11.145500Z

I guess you saw https://github.com/thheller/next-cljs ?

Alexis Vincent 2021-02-10T15:25:44.147400Z

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 Vincent 2021-02-10T15:27:21.148500Z

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

thheller 2021-02-10T15:28:24.148800Z

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

Alexis Vincent 2021-02-10T15:30:58.150400Z

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

thheller 2021-02-10T15:31:39.150700Z

about everything

Alexis Vincent 2021-02-10T15:31:46.151100Z

got you

thheller 2021-02-10T15:32:09.151600Z

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

thheller 2021-02-10T15:32:29.152200Z

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

thheller 2021-02-10T15:32:35.152500Z

but yeah its a massive amount of work

Alexis Vincent 2021-02-10T15:33:32.153700Z

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

thheller 2021-02-10T15:33:40.153900Z

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

thheller 2021-02-10T15:34:42.155100Z

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

thheller 2021-02-10T15:35:08.155700Z

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

thheller 2021-02-10T15:35:33.156600Z

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

thheller 2021-02-10T15:35:45.157Z

but to do it cleanly things need to be really different

Alexis Vincent 2021-02-10T15:36:06.157400Z

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

Alexis Vincent 2021-02-10T15:36:18.157600Z

I’ll DM you

thheller 2021-02-10T15:36:59.158300Z

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

bringe 2021-02-10T18:38:39.158900Z

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)
        ...

bringe 2021-02-10T18:39:25.159200Z

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

bringe 2021-02-10T18:46:52.159500Z

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.

thheller 2021-02-10T22:21:26.159900Z

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.

bringe 2021-02-10T22:40:07.160100Z

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.

bringe 2021-02-10T22:42:08.160500Z

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