cljs-dev

ClojureScript compiler & std lib dev, https://clojurescript.org/community/dev
thheller 2020-03-25T08:52:08.001200Z

whats the point of that? requires transpiling before it can be loaded. so might as well emit es6 directly instead and transpile that. I'm pretty sure the closure devs themselves don't recommend using goog.module anymore.

dnolen 2020-03-25T13:01:43.002300Z

@thheller they updated the Closure wiki 3 weeks ago recommending switching to goog.module - do you have a link that says different?

dnolen 2020-03-25T13:02:52.003200Z

I also I haven't seen any movement in the Closure Library to switch to ES6 modules, did you see something?

dnolen 2020-03-25T13:06:14.004100Z

Steve Hicks did mention they were considering it but the plans seem quite unclear (they might do TypeScript)

thheller 2020-03-25T13:07:04.004700Z

thats the last info I saw

thheller 2020-03-25T13:07:38.005400Z

goog stuff kinda works when using import Thing from "goog:goog.string"

dnolen 2020-03-25T13:09:36.006100Z

right that's pretty old

dnolen 2020-03-25T13:09:47.006600Z

this was updated 3 weeks ago

thheller 2020-03-25T13:10:07.007200Z

> Presently goog.module is recommended over goog.provide for new Closure files.

thheller 2020-03-25T13:10:29.007800Z

new closure files ... I think that is meant for the closure library. not sure that applies to 3rd party code

dnolen 2020-03-25T13:10:58.008500Z

I would say the messaging here is not very clear

dnolen 2020-03-25T13:11:12.009200Z

and Steve Hicks direct communication simply muddied the waters as to their intentions

thheller 2020-03-25T13:11:17.009300Z

but doesn't really matter if goog.module or ESM, right now that just complicates things. especially regarding hot-reload and doesn't really buy anything.

dnolen 2020-03-25T13:12:13.009900Z

right but like I said earlier

dnolen 2020-03-25T13:12:27.010300Z

debug loader may go kaput - so we may have to fend for ourselves anyway

thheller 2020-03-25T13:13:06.010800Z

hmm yeah I replaced that loader years ago in shadow-cljs so dunno what the state of the goog loader is

dnolen 2020-03-25T13:24:49.011400Z

but point taken, can probably drag our feet a bit longer and ES6 modules have the benefit of being loadable w/o transpilation

dnolen 2020-03-25T13:25:04.011700Z

(in browser & Node.js)

dnolen 2020-03-25T13:25:22.011900Z

thanks for the feedback

dnolen 2020-03-25T13:26:00.012400Z

@thheller re: ESM how would that complicate hot loading?

dnolen 2020-03-25T13:26:22.013Z

I thought just making defs var instead of const was enough for this to work

thheller 2020-03-25T13:26:53.013500Z

well real ESM you can't hot load at all since there aren't any global vars to replace

thheller 2020-03-25T13:27:52.014400Z

right now we have some.ns.foo = function() ... and just "overwrite" some.ns.foo on the next load

thheller 2020-03-25T13:28:26.014900Z

in ESM only the rewritten version allows that since it rewrites to be global again

thheller 2020-03-25T13:29:07.015500Z

otherwise you have let foo = function() ... or so in a module but you can't load the replacing code into that module scope

dnolen 2020-03-25T13:29:28.015800Z

hrm yeah that's what I remembered

dnolen 2020-03-25T13:29:42.016400Z

that's the problem w/ ESM module export - is that it's really a capture

dnolen 2020-03-25T13:29:50.016600Z

by the module that uses

thheller 2020-03-25T13:32:04.017700Z

yeah I experimented a bit with ESM in the past but interop with the closure lib is annoying and other issues due to no shared global scope

thheller 2020-03-25T13:32:45.018700Z

it would be neat if CLJS compiler output could just be consumed as regular ESM by any other tool but that would currently mean getting rid of the closure-library either completely or rewriting the pieces we use to ESM

thheller 2020-03-25T13:32:57.019100Z

which isnt' actually a big deal since cljs.core doesn't use that much

thheller 2020-03-25T13:33:09.019400Z

but still likely breaks build where people use more

dnolen 2020-03-25T13:35:08.020400Z

@thheller right ESM has the REPL problem we just talked about

dnolen 2020-03-25T13:35:28.021Z

so it doesn't seem like a good target - unless you're talking about a more subtle strategy I don't understand

thheller 2020-03-25T13:35:49.021500Z

strict ESM output so all other JS tools work

thheller 2020-03-25T13:36:04.022200Z

to keep REPL and hot-reload we just transpile it back down to one shared global scope

dnolen 2020-03-25T13:37:14.023500Z

that's an interesting project (perhaps very related) - but the second part is the one I'm mostly concerned about now

thheller 2020-03-25T13:38:38.024600Z

yeah the transpile mode from closure just rewrites let foo = "thing" based on the filename so var foo$$module$some$file = "thing" or so

thheller 2020-03-25T13:39:00.025100Z

so technically thats just a regular global var we can dynamically manipulate or overwrite

thheller 2020-03-25T13:39:06.025300Z

in the browser thats no issue at all

dnolen 2020-03-25T13:39:42.026100Z

though that's treading into pretty yucky territory - since it's relying on the renaming strategy

thheller 2020-03-25T13:40:32.026800Z

thats fine IMHO. the names are stable and predictable

thheller 2020-03-25T13:40:56.027700Z

there is another transpile mode for compiling ESM->CJS that I haven't tried yet

thheller 2020-03-25T13:41:06.028200Z

but that likely is annoying again because no shared global scope

dnolen 2020-03-25T13:41:06.028500Z

I mean who knows if they'll be stable and predictable

dnolen 2020-03-25T13:41:10.028700Z

that stuff isn't public far as I know

dnolen 2020-03-25T13:43:30.029700Z

but rewinding now, another alternative - we don't care what Closure does

dnolen 2020-03-25T13:43:40.030Z

since the optimizer works on the lowered global form

dnolen 2020-03-25T13:49:46.030800Z

i.e. goog.provide(...) is really a triviality - could easily be cljs.namespace(...)

thheller 2020-03-25T13:51:21.031200Z

well that wouldn't be recognized by the closure-compiler when going through :advanced

dnolen 2020-03-25T13:51:40.031900Z

but trivial to preprocess in that case

dnolen 2020-03-25T13:52:35.033400Z

my point here is break down the problem in some simple options / goals

dnolen 2020-03-25T13:52:48.034100Z

so just enumerating what "we don't care" look like

thheller 2020-03-25T13:54:05.034900Z

well IMHO if changes are made the goal should be ESM output

thheller 2020-03-25T13:54:22.035300Z

otherwise goog.provide is fine

thheller 2020-03-25T13:54:34.036Z

replacing the debug loader is easy and can still use those primitives

dnolen 2020-03-25T13:54:51.036400Z

I'm only saying alternative goog.provide because it may just go away forever

dnolen 2020-03-25T13:54:56.036600Z

they've started linting it

thheller 2020-03-25T13:55:55.037400Z

goog.module imho is bad. still not consumable by other tools and just complicates our story as well

dnolen 2020-03-25T13:56:07.037700Z

sure I agree w/ that

thheller 2020-03-25T13:56:33.038300Z

replacing the debug loader is trivial

dnolen 2020-03-25T13:56:50.038800Z

yeah I'm not so concerned about the debug loader

dnolen 2020-03-25T13:57:13.039300Z

I mean it's clear we can proceed as we have for years w/ very few changes

thheller 2020-03-25T13:58:34.040200Z

another thing that we would have been better from the start is not adopting the "nested" namespaces in the first place

thheller 2020-03-25T13:58:41.040600Z

but dunno if its maybe too later to change that

thheller 2020-03-25T13:59:09.041200Z

but cljs.core/assoc could just be var ns$cljs$core = {} for the ns and then ns$cljs$core.assoc = ...

thheller 2020-03-25T13:59:35.041600Z

no goog.provide or goog.require needed at all

dnolen 2020-03-25T14:00:08.042100Z

I mean there's a browser usability issues here

dnolen 2020-03-25T14:00:28.042700Z

how it is now is plenty inspectable in the browser

thheller 2020-03-25T14:01:07.043300Z

dunno if that changes much. the objects are still easily inspectable

dnolen 2020-03-25T14:01:23.043900Z

it would change a lot

dnolen 2020-03-25T14:01:28.044300Z

autocomplete becomes way worse

dnolen 2020-03-25T14:01:45.045100Z

anyways - I'm not saying not a bad idea - but the tradeoffs are definitely there

thheller 2020-03-25T14:02:25.045800Z

some tools also rely on the lookups by nested names so they'd all break

thheller 2020-03-25T14:03:10.047Z

but gets rid of a bunch of issues too since there'd be no more clashes for (ns foo.bar) (def thing "x") and (ns foo.bar.thing)

dnolen 2020-03-25T14:03:26.047200Z

I mean part of this illustrates how bad ESM wrt. REPL based developed

thheller 2020-03-25T14:03:39.047800Z

yeah ESM is horrid for anything dynamic

dnolen 2020-03-25T14:03:50.048300Z

unsurprising since the Racket people worked on it and there's not a good hot-loading narrative there

dnolen 2020-03-25T14:03:59.048800Z

since they didn't like it in a teaching context

thheller 2020-03-25T14:04:36.049400Z

but it is the standard we have and gaining access to all other JS tools would open up many possibilities

thheller 2020-03-25T14:04:53.050100Z

transforming it into something usable in a dynamic setting is not so bad either so might be worth

thheller 2020-03-25T14:05:08.050800Z

but I don't like ESM myself at all

dnolen 2020-03-25T14:05:10.051Z

I'm not personally interested in JS tooling and never think about - what do you have in mind that you think would be useful

dnolen 2020-03-25T14:05:23.051500Z

or users would find useful in their projects?

thheller 2020-03-25T14:05:47.052Z

things like https://storybook.js.org/ become immediately usable

💯 1
thheller 2020-03-25T14:06:14.052600Z

right now we basically re-invent all the tools because they can't load our code

dnolen 2020-03-25T14:07:25.053700Z

@thheller instead of starting with ESM, what do you perceive as issues w/ just optionally generating ESM for those use cases?

dnolen 2020-03-25T14:07:42.054200Z

I feel like if you really want ESM then maybe you don't care about the REPL that much anyway

thheller 2020-03-25T14:08:27.054900Z

so one of the issues I ran into when experimenting is with ESM you can't just assume there is a global scope

dnolen 2020-03-25T14:08:59.056Z

what I mean is let's consider this as orthogonal thing

thheller 2020-03-25T14:09:03.056400Z

so you can't just access stuff which complicates some macros. say a macro generates code using (goog.string/something) but the namespace using that macro didn't have a require for the goog.string

dnolen 2020-03-25T14:09:22.057Z

User A wants to use StoryBookJS - they can pass :cljs-es6-module-format or whatever

thheller 2020-03-25T14:09:26.057300Z

so tracking references becomes a bit more complicated

dnolen 2020-03-25T14:10:22.058700Z

@thheller right that's true, the implicitly loaded nses thing is a problem in the wild

thheller 2020-03-25T14:11:57.059400Z

yeah lots of code relies on global references since the compiler doesn't really verify those and people like to cheat 😉 https://clojure.atlassian.net/browse/CLJS-712

thheller 2020-03-25T14:15:04.060600Z

ESM still feels like a work in progress in many areas though

thheller 2020-03-25T14:15:25.061200Z

so might just be best to wait till import maps and stuff become better supported

dnolen 2020-03-25T14:17:31.061700Z

not familiar w/ import maps (looking a bit now), how would that help?

2020-03-25T14:22:17.064100Z

@thheller isn’t that goog.string problem present in current cljs as well? best practice is to have cljs namespace doing implicit macro requires with all needed requires and document that macros must be used through that cljs namespace only (to force all requires as well), wouldn’t this strategy work with ESM as well?

dnolen 2020-03-25T14:23:04.064600Z

well currently we don't warn

dnolen 2020-03-25T14:23:11.065Z

we used to but it's wasn't Clojure-y

thheller 2020-03-25T14:24:14.066300Z

import maps aren't related to CLJS in any way. just make ESM more bearable, otherwise it is too strict and probably the reason it isn't as widely adopted. eg. react still doesn't ship ESM code.

thheller 2020-03-25T14:25:28.067200Z

@darwin it isn't present as long as there is a global shared scope and something loaded that namespace before you accessed it

2020-03-25T14:27:48.068800Z

yes, but that is not always the case, e.g. when I use a macro from some library first time and it generates code which uses some namespaces I have no clue about, I only discover it at runtime that those are missing and I have to require them

2020-03-25T14:28:11.069100Z

at least in dev mode, I believe

thheller 2020-03-25T14:28:22.069300Z

yes but thats the fault of the library

thheller 2020-03-25T14:28:58.070100Z

not the thing I'm talking about

2020-03-25T14:30:16.071100Z

ok, but cure for this via “going through cljs namespace” would work for that goog.string problem with ESM, no? that was my original curiosity

thheller 2020-03-25T14:30:29.071300Z

(ns foo.bar ;; cljs
  (:require-macros [foo.bar])
  (:require [goog.string]))

(ns foo.bar) ;; clj
(defmacro thing [& args]
  `(goog.string/foo ~@args))

(ns foo.consumer
  (:require [foo.bar :as bar]))

(bar/thing 1 2 3)

thheller 2020-03-25T14:30:49.071700Z

foo.consumer would have no direct import for goog.string yet use it directly

thheller 2020-03-25T14:31:02.072100Z

so the code generator would need to detect that and add it

thheller 2020-03-25T14:31:19.072500Z

nothing wrong with the macro code at all

thheller 2020-03-25T14:31:48.072900Z

can't and shouldn't expect the consumer to add a goog.string require

thheller 2020-03-25T14:32:09.073300Z

but its not too hard for the compiler to detect that

2020-03-25T14:33:17.073800Z

ok, good, thanks for your answer

thheller 2020-03-25T14:38:39.074200Z

I'm not a fan of ESM at all but it is better than CommonJS etc

thheller 2020-03-25T14:39:10.074900Z

I still think the closure approach of namespacing everything into one shared global scope is best

thheller 2020-03-25T14:39:23.075300Z

sadly that isn't the way the world is going

thheller 2020-03-25T14:39:59.076200Z

but at least with ESM we can transpile to get that world when people follow the spec

2020-03-25T15:07:06.077700Z

considered this trickery to get back global scope with ESM? https://mathiasbynens.be/notes/globalthis https://github.com/ungap/global-this/blob/master/esm/index.js

2020-03-25T15:26:59.078Z

just did a quick test with node: https://github.com/darwin/esm-trickery

thheller 2020-03-25T15:45:03.079Z

thats horrible ... much better to just use ESM and compile it down. that at least has rules.