Fork me on GitHub

I'm making a scripting tool for node, but I'm in a bit of a CommonJS / ESM style conflict. So for example path is required as (:require ["path" :as path]), this is the default style which only works with CommonJS. Some libraries now only expose ESM in their newest version. E.g. term-size must be required using (:require ["term-size$default" :as term-size]) because it's exposed as an EcmaScript module. But it's probably not good to mix CommonJS and EcmaScript in one namespace form, is it? My tool can support it, but it's just a matter of: is it a bad idea? If styles cannot be mixed, then (:require ["path" :as path]) has to become (:require ["path$default" :as path]) which is more verbose. So the question is: do I go with the more verbose $default style of import, so all ESM libs can also be required in the same style, or should I consider some other solution?


What happens when you write a "normal" CLJS library for node which requires (:require ["path" :as path]) and then require that library in a project which is a compiled as an ESM module?


compiling CLJS to an ESM module is already in pretty unpaved territory. i'm not sure what would happen; probably would depend on the build tool


maybe stupid question: how do you handle aliasing with ESM that don't have a default export?



(:require ["foo" :as foo])
where foo only has named exports?


@borkdude this was the reason for leaning on Webpack or any Webpack-like bundler - to punt this problem to where it belongs


as far as I can tell all import patterns are supported by ClojureScript because it's not our problem


you cannot control what libraries people want to use


you can longer expect people to lower to some common JS standard


since built in modules export both a default object and named exports, if you handle aliasing with non-default exports then you might not need to change anything for importing built ins, which I think would be the biggest worry


in which case I would default to all-ESM


@lilactown Currently (:require ["foo" :as foo]) is implemented using require(), but this brings the limitation that I'm currently trying to address: you can't load ESM modules using that


@borkdude you mean if you don't use a bundler?


@dnolen this is a custom tool that doesn't use the normal CLJS tooling. it's a one-off scripting tool that interprets the ns form on its own and then uses dynamic require or dynamic import (the latter is needed for ESM)


@borkdude but that's what I'm saying - are you going to let people load arbitrary modules from NPM?


if you are then you need to use a bundler


actually I tried (:require ["path" :as path]) using dynamic import and it just works as before, while path is an object with a default object inside of it. Hmm, perhaps there isn't a problem at all then. @dnolen yes, arbitrary modules, but those modules are installed via npm install foobar. my tool loads them from the script directory at runtime, no bundling


anything else means users cannot use whatever they - want following the existing documentation


@borkdude I'm telling you - if you don't use a bundler then you do not let people arbitrary modules


arbitrary modules means using a bundler


the ship sailed a very long long time ago


that doesn't make sense to me. if borkdude's loading these libs into Node.js, he needs to ensure his code calls the library correctly - but otherwise Node.js shouldn't require a bundler AFAICT


I don't know why I need a bundler, sorry. Perhaps I'm just misunderstanding what this is. This currently works with the tool.

$ npm install csv-parse
$ npm install shelljs

(ns script
  (:require ["csv-parse/lib/sync" :as csv-parse]
            ["fs" :as fs]
            ["shelljs" :as sh]))

(println (count (str (fs/readFileSync "script.cljs"))))

(prn (sh/ls "."))

(prn (csv-parse "foo,bar"))


@borkdude oh sorry this only for scripting in Node.js


so when switching the resolve+loading of npm libs to all ESM-style, then ["shelljs" :as sh] becomes ["shelljs$default" :as sh] in the scripts, that's the issue I'm trying to address here: it would perhaps be annoying if users had to write $default a lot, but perhaps it's for the better to make it more predicable what's happening, without introducing magic

Adam Stokes15:08:40

For the value that nbb gives I think it's entirely acceptable to ask consumers to type out a few extra characters 🙂


yeah I think it's best to pick one module resolution pattern. that seems like a "learn once, works forever" w.r.t. using ESM with nbb


@borkdude plus that's how it works for ClojureScript anyway


doing it different will just lead to confusion - different docs


I'm not sure, it might depend on how shelljs gets bundled with your ClojureScript, since it's a CJS module


it doesn't get bundled


all npm modules are resolved at runtime


while I think shadow-cljs is a fine tool - it's one of the thing I like about the least - that it's bifurcating people understanding of requires - I understand that it needed to solve a problem we didn't solve first - but it's muddied the waters for sure


relative to the script


(I meant in the ClojureScript case)


now that there's a standard pattern - just support the standard pattern as the main thing


there's some essential complexity here that isn't just shadow-cljs muddying the waters


knowing how your deps will be imported in your CLJS code (not talking about borkdudes tool atm) requires understanding your bundler and how CLJS will interact with it


because ESM and CJS deps are handled differently by your bundler


the question that borkdude was raising was about how to handle CJS dependencies if he goes all in on emitting ESM code for his scripts


and stop trying to make thing's easy


it just creates more confusion later


so ESM is "the future" in these modules systems? betting on this is safe..?


yes I think it's pretty fair to say that a lot of new code is written in that style


Node.js is going to be in mixed-mode for awhile AFAICT, due to the differences between CJS and ESM. but the community does seem to be slowly migrating


it's probably on the order of years, not decades, at least 😛

Alex Miller (Clojure team)15:08:33

but aren't years in the JS community like decades in real life?

☝️ 11
🙈 6

$ npm install zx # ES module
$ nbb -e '(require (quote ["zx$fs" :as zxfs])) (zxfs/existsSync ".")'

🎉 16