17:40
<Justin Ridgewell>
đź‘‹ just discussed module reflection, lazy, and import assertions with my team
17:43
<Justin Ridgewell>

A few notes we have:

  • the import module syntax is acceptable if we can't move this into the assertions
  • If we do move into assertions, we really should rename assert (we might need to do this anyways based on implementer feedback in https://github.com/tc39/proposal-import-assertions/issues/125)
  • If we move this into assertions, we can simplify the 2nd param to dynamic import (instead of import("", { assert: { key: value } }), just make it import("", { key: value }))
  • The module in import module is confusingly named, I'm already importing from ES modules
17:43
<Justin Ridgewell>
So I'm not going to lone block import reflection anymore, but would still very much like to move it into assertions
17:54
<Kris Kowal>

At this point, I’m in favor of changing the shape of import reflection to import example from 'example.com' with { reflect: true } and import('example', { reflect: true }), which would imply import assertions would look like import example from 'example.com' with { type: 'e.g.,destination' } and import('example.com', { type: 'e.g.,destination' }).

If our constituents demand that the type string key must be communicated to the import hook, for example to direct content-negotiation, I can be convinced on the condition that the type must be threaded thru importHook. Evidently, the web platform doesn’t wish for this to be an assertion at all, since the type can be ignored and the response content-type dictates what kind of module source it will produce.

I will be difficult to convince that the with parameters be opened up as an arbitrary key-value space that virtual modules can fiddle with because of the internal complications that implies for memoizing import. I want TC39 to curate this space and be free to extend it with other properties, like reflect, lazy, phase or so on, with behaviors that can’t be emulated by an importHook.

17:57
<Kris Kowal>
My opinion shifted in that direction because our SES shim for “hardened JavaScript” censors dynamic import to deny guest programs an escape hatch, and for that to continue being effective going forward, import.module, import.reflect, or import.anything would be problematic. I don’t expect that argument to convince anyone else that we should funnel reflection through dynamic import, but I also don’t expect anyone else to need to be convinced!
18:01
<Kris Kowal>
In any case, the behavior of an importHook doesn’t depend on the reflect parameter, so I don’t think it should be communicated in an options bag. The behavior of importHook would also not vary based on yulia’s proposed lazyInit (by whatever name) either. There’s an implied phase or goalState parameter that currently defaults to "loaded" if reflect: true and defaults to "evaluated" otherwise. Neither of those should be communicated to importHook.
18:02
<Kris Kowal>
If we did expose an options bag, we’d need something analogous to HTTP cache-control headers to dictate what properties of the options bag should be incorporated in the module key and in what order. We don’t have a suitable position to stand for those to be consistent between modules or scopes of modules (like packages).
18:04
<Justin Ridgewell>
(Can wait till after your current thoughts are down, but I disagree with the not-being communicated to importHook and it not affecting the import behavior)
18:04
<Kris Kowal>
So, my reasoning is that we have to consider why we’d want an arbitrary options bag, and if there’s a better way to solve the same problem. My reasoning is that it’s relatively straight-forward to construct Node.js-alike behavior in terms of the current harmony state, using out-of-band information (e.g., package.json) that keys most of these choices on the specifier, and imposes coherence across all modules in scope.
18:05
<Kris Kowal>
(Can wait till after your current thoughts are down, but I disagree with the not-being communicated to importHook and it not affecting the import behavior)
A concrete case will help me understand your objection.
18:05
<Kris Kowal>
And to be clear, I mean for a subset of the with options to be communicated to importHook, specifically type.
18:06
<Kris Kowal>
On the premise that the engine knows to incorporate type in the memo key.
18:07
<Justin Ridgewell>
This doesn't come up until Stage 2 of compartments, right, so I'm not objecting to anything currently
18:07
<Justin Ridgewell>
Why not pass the full options bag to import hook?
18:08
<Justin Ridgewell>
My mental model is that the lazy and module keywords are evaluators of the imported module, and should be passed to import
18:08
<Justin Ridgewell>
And it just starts getting weird if TC39 has to standardize the keys that are passed to it
18:09
<Kris Kowal>
Passing arbitrary key values to the options bag creates composition hazards. Consider the case that A imports 'my.ttf' with bold and B imports 'my.ttf' with italic. Application C imports A and B. There is a reasonable expectation that the environment coördinates these such that in general, A and B get the same module instance.
18:10
<Justin Ridgewell>
A loaders option is the case that we're currently interested in, but that's definitely not a TC39 concern (and I'm not sure how it'd be done at runtime so this isn't a perfect use case)
18:11
<Kris Kowal>
Loaders doesn’t require the loader to be expressed in individual modules.
18:11
<Justin Ridgewell>
See https://github.com/tc39/proposal-import-assertions/issues/125#issuecomment-1340173901, not passing the assertions is also a composition hazard
18:12
<Kris Kowal>
It’s straightforward to key the loader off the extension and map it to a behavior out-of-band, in a way that will apply to all modules in the same scope, preserving singleton modules.
18:12
<Kris Kowal>
All the more straightforward with Layer 0 in play.
18:12
<Kris Kowal>
Though I will agree that functionality should also be implemented by import maps.
18:12
<Justin Ridgewell>
I don't see these cases as being separate? All assertions are possible out of band, so why have any inline?
18:13
<Kris Kowal>
And specifically in the hardened JavaScript case, we’ll want to isolate the loaders in their own “compartments”. It’s a fun scenario to implement.
18:14
<Kris Kowal>
I don't see these cases as being separate? All assertions are possible out of band, so why have any inline?
I agree! My personal preference would be to not entertain assertions. But, I will also not block them, provided they compose well with the module memo.
18:14
<Kris Kowal>
I vehemently agree.
18:15
<littledan>
I agree with the 90% of what you two are saying which overlaps, and I could see things either way for the remaining 10%!
18:15
<Justin Ridgewell>
I think ergonomics will suffer because of it.
18:15
<littledan>
vehemently so
18:15
<Justin Ridgewell>
Inline configuration is just easier to do
18:15
<littledan>
I could honestly see things either way on TC39 vs yolo to maintain the space of attribute keys
18:16
<Kris Kowal>
“Faster, easier, more seductive”
18:16
<littledan>
(leaning towards TC39 tbh)
18:17
<littledan>
it would be pretty nice to have keys that are entirely handled by the JS spec. Both reflect and lazyInit make sense for this.
18:17
<Kris Kowal>
I’m also trying to recapitulate the creation of a closet industry of WebPack Configuration Engineers, which just falls out from failing to allow libraries to configure themselves locally. I think we agree on that.
18:17
<Justin Ridgewell>
Oh man, don't make me go back to specifying loaders in config, I don't want https://esbuild.github.io/api/#loader again
18:17
<littledan>
OK, I think this is actually the core disagreement: some people think it's good to factor the configuration out into a separate file and some people think it should be inline
18:17
<Justin Ridgewell>
Static inline is just so nice to deal with during tooling
18:18
<littledan>
I think we should dig into this more somehow. We've just been shouting opposite assertions at each other on this topic, so far
18:18
<Kris Kowal>
I would suffice it to say, have done that differently https://github.com/gutentags/system#extensions
18:19
<littledan>
If we do want inline configuration, this isn't necessarily incompatible with a TC39-curated list of top-level keys. We could, in theory, reserve a particular key for this purpose
18:20
<Kris Kowal>
For the record, I agree that inline configuration is nice. I just think it’s an attractive nuisance.
18:20
<littledan>
this key could be rejected at runtime, or ignored at runtime (or we could have two keys, one with each behavior...)
18:20
<littledan>
(this is assuming that you can embed further objects inside of that key)
18:20
<Kris Kowal>
(Aside from a prior conversation: And I also agree littledan that having the major version in a specifier is a good alternate universe, as in Go.)
18:20
<littledan>
And I also agree littledan that having the major version in a specifier is a good alternate universe, as in Go.
We actually do this internally in Bloomberg and it works really well; I totally recommend it.
18:21
<littledan>
but yeah it is too late
18:22
<Kris Kowal>
(In the Go ecosystem, incorporating the major version in the name allows libraries to gracefully migrate implementation between major version trains, since applications can have a singleton of both versions.)
18:22
<littledan>
aside: If we do switch to with, we might consider a syntax which is a little nicer, with fewer brackets, like import json from "./foo.json", type: "json". This could extend to arbitrary keys without ASI hazards.
18:22
<Kris Kowal>
It’s never too late to make a name2 package.
18:23
<littledan>
assert was essential to be explicit, since this was chosen to indicate the mental model. with doesn't mean anything in particular.
18:23
<Kris Kowal>
The colons might even be unnecessary.
18:23
<littledan>
eh I guess so, but the comma is necessary
18:23
<littledan>
to avoid ASI hazards
18:24
<littledan>
it becomes more important if you have multiple things attached; with just one assert it is manageable
18:24
<littledan>
we could use C++ initializer list syntax! the possibilities are endless! import json from "./foo.json", type("json") {}
18:24
<littledan>
the {} is just for fun
18:26
<nicolo-ribaudo>
the {} is just for fun
It's to incorporate module declarations in that syntax!
18:26
<littledan>
I guess with a colon, it gives an intuition of "these are arbitrary key/value pairs" and without, it feels like "this is a keyword that TC39 made" (probably I'm overthinking this)
18:26
<Kris Kowal>
If we do want inline configuration, this isn't necessarily incompatible with a TC39-curated list of top-level keys. We could, in theory, reserve a particular key for this purpose
Returning to the theme, are you concretely suggesting something like import example from 'example.com', type 'woff2', lazyInit true, etc {bold: true, italic; true}?
18:27
<Justin Ridgewell>
Lol, one of the suggestions was to not have a keyword import foo from 'foo' { type: 'json' }
18:27
<littledan>
Returning to the theme, are you concretely suggesting something like import example from 'example.com', type 'woff2', lazyInit true, etc {bold: true, italic; true}?
yeah this is what I was suggesting
18:27
<Justin Ridgewell>
(with appropriate NLT)
18:27
<Kris Kowal>
Where, etc is not incorporated in the memo key?
18:27
<littledan>
I would argue that anything in etc should be rejected in non-tooling
18:28
<littledan>
that is, the whole syntax of , etc {...} would be tooling-only syntax
18:28
<Kris Kowal>
Ah, like TypeScript comments.
18:28
<littledan>
well, maybe it would be ignored at runtime, or maybe rejected. type annotations are based on the "ignore" idea.
18:28
<littledan>
my intuition was rejected but Rob was leaning ignore
18:29
<littledan>
rejected is compatible with just not mentioning the etc key in the spec at all :)
18:29
<Kris Kowal>
rejected is compatible with just not mentioning the etc key in the spec at all :)
True
18:30
<Kris Kowal>
(with appropriate NLT)
Pardon my ignorance, NLT?
18:30
<littledan>
also, if we have a fixed set of keys, we can say that some of them don't bother with arguments. So we can do import example from './path', lazyInit
18:30
<Justin Ridgewell>
No Line Terminator, it's to prevent ASI hazards
18:30
<littledan>
or, to create them!
18:30
<Justin Ridgewell>
https://tc39.es/ecma262/multipage/notational-conventions.html#sec-no-lineterminator-here
18:31
<Kris Kowal>
Yeah, I’m familiar. Just never internalized the initialism. Thank you!
18:33
<Kris Kowal>
Justin Ridgewell: How do bundlers currently deal with the scenario I presented above, with a diamond dependency and conflicting hints? Do these scenarios just not occur in practice, or just seldom enough that it’s easy to live with arbitrary merge rules?
18:35
<Kris Kowal>
I could easily see libraries responding to bugs that emerge from arbitrary conflict resolution with the old “doctor doctor it hurts” / “stop hitting yourself”
18:35
<Justin Ridgewell>
In esbuild/turbopack I would be using special specifiers to communicate to the bundler, which means they're individual instances
18:36
<Justin Ridgewell>
I'm not sure how webpack handles it's inline loader specifier, if it performs dedupe or throws
18:36
<Kris Kowal>
So the specifiers and the meta would need to agree?
18:36
<littledan>
I think such cloning is more acceptable for some kinds of assets than for stateful code
18:36
<littledan>
people don't really want their stateful modules to be cloned
18:36
<littledan>
especially if they forget they are stateful
18:36
<Justin Ridgewell>
This isn't something I usually hit, though, because importing a special loader module is usually handled by one parent module that wraps
18:36
<Kris Kowal>
or identity discontinuity surprises
18:37
<littledan>
right that too
18:37
<Kris Kowal>
Yeah, I agree that with care, the hazard can be avoided.
18:37
<Justin Ridgewell>
Yah, esbuild has no deduping unless the loader plugin specifically does it
18:38
<littledan>
this is specifically why we didn't want to have arbitrary uninterpreted evaluator attributes that you could access with import.meta.attributes--because the implicit cloning is unintuitive.
18:38
<Kris Kowal>
And also that the importHook is in a position where it can implement an arbitrary policy for duplicating, sharing, or rejecting for conflicts, as long as it knows all the keys used by the corresponding user code.
18:39
<Kris Kowal>
It sounds like we agree that the specifier should be the only memo key though, which is interesting.
18:40
<littledan>
It sounds like we agree that the specifier should be the only memo key though, which is interesting.
hmm, I'm not sure that's always true, I'd need to think more about it
18:40
<littledan>
definitely not true if you want to configure assets sometimes
18:40
<littledan>
for JS code... maybe...
18:40
<Kris Kowal>
I mean, it seems like Justin Ridgewell always uses unique memo keys to avoid the hazard, at least.
18:41
<Kris Kowal>
The trouble is that importHook is not in a position to choose the memo key based on arbitrary import etcdata.
18:41
<Justin Ridgewell>
That's just a side-effect of only the specifier being extensible, not because I specifically designed it that way
18:41
<Kris Kowal>
Because the importing module dictates the memo key and uses it to memoize the promise returned by importHook.
18:42
<littledan>
That's just a side-effect of only the specifier being extensible, not because I specifically designed it that way
well, we're discussing whether the specifier should be extensible...
18:42
<Justin Ridgewell>
If I moved from special specifier to module attributes, I think the output should be similar, which would mean it's up to the loader to dedupe
18:42
<Justin Ridgewell>
Sorry, I'm using "specifier" to reference the string literal
18:43
<Justin Ridgewell>
If you're including attributes as part of "specifier", I was using a different meaning
18:43
<Kris Kowal>
I only use “specifier” to refer to a string, and use “module memo key” in cases where the specifier might not necessarily be equivalent.
18:47
<Kris Kowal>
An interesting scenario is example.woff?bold&italic vs example.woff?italic&bold.
18:48
<Kris Kowal>
Using specifiers leaves a degree of freedom to the import site where, failing to canonicalize the query string, they effectively control whether they load the same asset twice.
18:48
<littledan>
If I moved from special specifier to module attributes, I think the output should be similar, which would mean it's up to the loader to dedupe
right, so, this raises the question: what should be the behavior when we don't have a builder-based loader
18:48
<Kris Kowal>
Perhaps not that interesting. The importHook is in a position to canonicalize every key it knows about. It’s also in a position to decide whether to refer to a canonicalized import specifier.
18:49
<Kris Kowal>
right, so, this raises the question: what should be the behavior when we don't have a builder-based loader
Presumably, a host loader would ignore the etc data.
18:49
<Kris Kowal>
Or reject if there are any.
18:50
<littledan>
Presumably, a host loader would ignore the etc data.
the reason I'm skeptical of this is because it would have different semantics from what the build tool would do. And, if we don't want cloning, the information wouldn't be visible through import.meta
18:52
<Justin Ridgewell>
With a importHook, I view that as a loader, so I would pass everything and let it decide the same way my build-time loader does.
Without a hook, I kinda think the browser should reject any it doesn't understand, and perform deduping on matching attributes
18:53
<Justin Ridgewell>
Deduping here being the controversial part
18:54
<Justin Ridgewell>
As I said in https://github.com/tc39/proposal-import-assertions/issues/125, I don't think there must be only one representation of a module, just that it might be a bug to have multiple in some cases
18:55
<Kris Kowal>
We could make that safer by requiring the importHook to express what it took into account. The only remaining problem with memo keys is the case that a single module repeatedly imports with the same specifier and varying etc.
18:56
<Justin Ridgewell>
Doesn't importHook return a module instance, or does it return metadata for the browser to perform the load?
18:56
<Justin Ridgewell>
If it returns an instance, why have it return anything else?
18:56
<Kris Kowal>
The importHook is obliged to return a Module instance.
18:57
<Kris Kowal>
With a importHook, I view that as a loader, so I would pass everything and let it decide the same way my build-time loader does.
Without a hook, I kinda think the browser should reject any it doesn't understand, and perform deduping on matching attributes
This entrains the concern of a specific kind of deep equality.
18:57
<Justin Ridgewell>
That's a loader concern, though, not a browser concern
18:58
<littledan>
Yeah I agree that, in general, loaders should reject attributes they don't understand, rather than ignoring them. So, on the web by default, if you used etc for anything, it would fail to load
18:58
<littledan>
Then, the question is: do we want custom import hooks to be able to tie into etc, or do we want that to be an error as well?
18:59
<Kris Kowal>
Yeah I agree that, in general, loaders should reject attributes they don't understand, rather than ignoring them. So, on the web by default, if you used etc for anything, it would fail to load
And it would be an easy mistake to write an importHook that ignores the etc. It would in fact be the default first pass at any importHook.
19:02
<Kris Kowal>
I think this herds us into a particular solution space, where a translating bundler is already in the only right place to have an opinion about etc metadata, and is also in a position to erase it.
19:05
<Kris Kowal>
Then, tragically, using etc metadata locks a portion of the ecosystem into using one of a compatible cohort of translating bundlers.
19:06
<littledan>
yeah, this is the reason why I lean towards TC39 specifying all of the keys and etc not being one of them
19:06
<littledan>
it'd be fine for tools to extend the language and make etc but it's not something I'm convinced we should encourage
19:06
<littledan>
fundamentally, use of etc is not aligned towards unification of the language semantics
19:13
<Justin Ridgewell>
Agreed, but I think it's helpful to have a syntax reservation for these use cases
19:13
<littledan>
maybe the syntax reservation can be similar to how we reserve TS syntax now: it's a parse error, and we promise to keep it that way
19:13
<Justin Ridgewell>
I just had to implement new URL('foo.txt', import.meta.url) support, and it's god-awful complication because of the SSR and CSR splits we have to handle
19:14
<littledan>
yeah I agree we absolutely need asset references
19:14
<Justin Ridgewell>
Allowing me to implement type: 'text' now without waiting for TC39 to standardize would make this usecase much nicer
19:14
<Kris Kowal>
Same. We need asset references.
19:14
<Justin Ridgewell>
Asset references wouldn't solve it
19:14
<littledan>
so... the "without waiting" part is the part that concerns me. Our goal (or, my goal) is to define a common language.
19:15
<Justin Ridgewell>
Because I would still need different references in browser and node
19:15
<littledan>
I was picturing asset references would resolve to basically the equivalent of what new URL returns
19:15
<littledan>
so, in what way wouldn't it solve it?
19:15
<Justin Ridgewell>
I need to compile the code once for both envs, because the asset reference to address a file is different
19:15
<littledan>
could you elaborate on that?
19:15
<Justin Ridgewell>
With type: text, it's one interpretation and I can do it as if it were a real JS module
19:15
<Kris Kowal>
For what it’s worth, Endo’s bundler already does text and bytes based on package metadata, for the same reasonable need.
19:16
<littledan>
With type: text, it's one interpretation and I can do it as if it were a real JS module
so, it sounds like you're not giving the whole code sample for what it is that you are implementing
19:16
<Justin Ridgewell>
For Browser, I need to ensure the request handler is prepped to serve the file, and write a http://localhost/path/to/file
For node, I need a file://absoltue/path/to/file and to copy the file to disk somewhere
19:17
<Kris Kowal>
And “module subgraph as an asset that needs to be bundled so I can portably hydrate a worker” is also something I’m very interested in.
19:17
<Justin Ridgewell>
type: 'text' would transform the imported file like https://gist.github.com/jridgewell/fa9754e38299d1f067e8aa8ac9ae336e#file-1-md does for JSON
19:17
<Justin Ridgewell>
Sorry, that was in reply to Dans' above comment
19:17
<Justin Ridgewell>
(I need to remember the reply feature…)
19:18
<littledan>
For Browser, I need to ensure the request handler is prepped to serve the file, and write a http://localhost/path/to/file
For node, I need a file://absoltue/path/to/file and to copy the file to disk somewhere
I'm having trouble understanding why asset references don't solve this
19:18
<Kris Kowal>
type: 'text' would transform the imported file like https://gist.github.com/jridgewell/fa9754e38299d1f067e8aa8ac9ae336e#file-1-md does for JSON
Same, but depending on whether Endo’s building a bundle or a zip archive.
19:18
<Justin Ridgewell>
Because the asset reference needs to be runtime value that can be used? How do I code an asset reference in today's ES2022?
19:18
<Kris Kowal>
I’m also interested in assets that entrain further asset dependencies.
19:18
<Justin Ridgewell>
The code output would be env dependent, because the way you access the file is env dependent
19:20
<littledan>
Because the asset reference needs to be runtime value that can be used? How do I code an asset reference in today's ES2022?
there aren't any asset references in ES2022, so that's not a question that can be answered...
19:20
<littledan>
however, I thought asset references would evaluate to a runtime value--that was always the idea, I thought
19:20
<littledan>
it'd be an environment-dependent signifier that you could use in an environment-dependent way
19:20
<littledan>
maybe it'd be the URL or maybe it'd be something else
19:21
<Justin Ridgewell>
So during bundling, the chunk which contains that runtime value would be env-dependent
19:21
<Justin Ridgewell>
I'd need to compile that twice, and also perform the copying to allow that file to be accesssed
19:22
<Kris Kowal>
Asset references should be accessed synchronously by value.
19:22
<littledan>
huh? I really don't understand what transformation you're thinking of
19:22
<littledan>
if you need the text, sure, type "text" seems reasonable, but the example you gave above was implementing new URL(..., import.meta.url)
19:23
<Kris Kowal>
You must be thinking that the transpiled form of an asset might just be a relative URL that the bundler arranges to resolve.
19:24
<Kris Kowal>
Or rather, the transpiled form is alternately a relative path or URL and either a Node.js or Browser API for obtaining the text.
19:24
<Kris Kowal>
As opposed to encoding as a string.
19:24
<Kris Kowal>
And that’s more germane in the CSS case where the transpiled form is probably just adding a link to the document.
19:26
<Kris Kowal>
Lots of stuff gets intertwingled in this space.
19:27
<Justin Ridgewell>
The point of the new URL("foo.txt", import.meta.url) example is that I need to access that file.
If I used an asset reference, how would I access that file?
In a browser, that reference would need to be http://localhost:3001/path/to/foo.txt
In node, that reference would need to be an absoulte/relative file path ../path/to/foo.txt
19:27
<Justin Ridgewell>
So the runtime value is dependent on execution env, right?
19:28
<Justin Ridgewell>
If I'm a bundler, and bundle that asset reference's runtime value into a larger bundle, that large file is now env dependent
19:29
<Justin Ridgewell>
That is an issue for my bundler, because it means I'm doing repeat work that could have been already cached
19:29
<Kris Kowal>
So, it’s useful to distinguish an asset module from an asset reference module, I think.
19:29
<Justin Ridgewell>
If I could just type: text import, then it's no longer env dependent, because the imported foo.txt file can be treated like another module without any other runtime value
19:30
<Justin Ridgewell>
Just a `default export "foo.txt string contents"`, and bundle that up into the larger file
19:30
<Kris Kowal>
There’s only one kind of asset module, but there are in fact environment dependent notions of an asset reference module (path, URL), and then further combinations if the notion is to make the asset reference portable (fetch, url module, fs module, filesystem API).
19:31
<Justin Ridgewell>
Exactly
19:32
<Kris Kowal>
Shimming an asset module is trivial (albeit gross), either embedding a string or a byte array or a base64 encoded string. Something like that. That covers one case.
19:32
<Kris Kowal>
And you can shim an asset module today the way you suggest for text.
19:32
<Kris Kowal>
Potentially an enormous bundle, and doesn’t capture the asset in a way that’s easy to pass around, like a URL.
19:33
<Kris Kowal>
Asset reference modules, and asset retrieval modules (a module that closes over both the reference and the means to load it, presumably async) remain…
19:44
<Kris Kowal>
I think the module harmony proposals provide an adequate foundation for these problems as written and having a import etc metadata reduces to the same argument we’ve tread today. You in fact have multiple options. With a virtual module source (even the lesser variant), you don’t even need to generate code for any of these cases. The downside is that you have to express an indication of your intent in the specifier. Ultimately, the argument hinges on whether the indication that a module is an asset, asset reference (host-dependent), or asset retriever (host-dependent), can be expressed in-band or out-of-band, and we digress into the argument we’ve already tread.
21:02
<littledan>
I am still confused by the connection Justin is drawing between whether it is a URL vs the text contents and whether it is cross-platform. It seems completely orthogonal
21:14
<Justin Ridgewell>
I'm not sure how to clarify it futher?
21:15
<Justin Ridgewell>
Text imports and asset references/URLS are orthogonal designs, my comments here are that URLs are a subpar experience because they are env specific
21:15
<Justin Ridgewell>
A text import is not platform specific
22:42
<Kris Kowal>
I could see importing a URL as analogous to import reflection, and being interesting if that could generalize to transitive dependencies.
22:46
<Kris Kowal>
I mentioned that there’s an implicit “goal state” parameter that has a different default for reflective import vs others. Goal states being: loaded, (transitively loaded), linked, (initialized), evaluated. The ones in parens are not interesting to a user, but being able to indicate or control loaded vs linked vs evaluated is interesting. Reflective import must not imply a goal state farther than loaded.
22:48
<Kris Kowal>
Perhaps analogous to import reflection, there’d be meta import, which would not execute but would vend out the import.meta (so the URL) of something (including assets) without attempting to execute it. I propose the default “goal state” for that would be “transitively loaded” or “linked”, because that would indicate to bundlers that the asset and its deps must be bundled.
22:49
<Kris Kowal>
Meta reflection lets us dodge the issue of URLs being a host-specific concern.
22:50
<Kris Kowal>
And this is a better solution than just exposing import.meta.resolve, because it can express dependency statically.
22:52
<Kris Kowal>
Concretely, the basic case, on the web: import kittyMeta from 'kitty.jpg', meta, goal "linked"; const kittyImg = document.createElement('img'); kittyImg.src = kittyMeta.url;
22:52
<Kris Kowal>
But also: import workerMeta from 'worker.js', meta, goal "linked"; new Worker().addModule(workerMeta.url)
22:54
<Kris Kowal>
One virtue of this approach is that it would work both in dev and prod, and with a bundler, without modification to sources.