| 17:40 | <Justin Ridgewell> | đź‘‹ just discussed module reflection, lazy, and import assertions with my team |
| 17:43 | <Justin Ridgewell> | A few notes we have:
|
| 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 If our constituents demand that the I will be difficult to convince that the |
| 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 |
| 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? |
| 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. |
| 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 |
| 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 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 |
| 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 |
| 18:30 | <Kris Kowal> | (with appropriate 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. |
| 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 |
| 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 |
| 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 etc data. |
| 18:49 | <Kris Kowal> | Or reject if there are any. |
| 18:50 | <littledan> | Presumably, a host loader would ignore the 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 |
| 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 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 |
| 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/fileFor 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 |
| 19:18 | <Kris Kowal> | |
| 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? |
| 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.txtIn 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. |