Closed trusktr closed 1 year ago
This is an interesting idea for a use case. Thanks for filing an issue. I take it that this is something that would be done within hosts, not decided in this proposal, right?
That sounds like a evaluator attribute, not a condition for the module to be loaded at all.
I guess that depends on some details; I could imagine a 'check' version of this in the context of something related to Node.js/ESM integration.
This would be really nice actually. I’ve been writing ESM modules that run in Node.js, browser and Deno w/o a compiler. Right now, I end up never using relative imports and instead using named imports so that they pass through the export map in Node.js and then I have to generate import maps for the browser and for Deno.
This would allow me to actually get rid of the last build/compile step. However, I’m not sure the syntax above is ideal.
What you likely want is an import to a single constant with a variation of the relative path on a per-platform basis.
import fs from "./fs-node.js" if { env: "node" }
import fs from "./fs-browser.js" if { env: "browser" }
import fs from "./fs-deno.js" if { env: “deno” }
This form probably isn’t possible given the existing syntax constraints, but it illustrates something closer to the ideal usage pattern.
It won't work with the assertion semantics because the first import that wouldn't met the env conditions will result in a failure.
While it's less elegant I can imagine that it will work with evaluator/transform attributes:
import fs_node from "./fs-node.js" with { env: "node" }
import fs_browser from "./fs-browser.js" with { env: "browser" }
import fs_deno from "./fs-deno.js" with { env: “deno” }
const fs = fs_node || fs_browser || fs_deno
env
would return undefined if the env isn't met, It's just an idea, not really a fan of it.
@xtuc that’s totally acceptable 😁
But wouldn't that fail the whole module graph? I think you would either need a new optional/weak import facility or dynamic imports to do it that way, and if you're stuck using dynamic imports you may as well use normal control flow rather than this env
assertion. (It would obviously be helpful to establish conventions for how to detect the nature of the environment, but this doesn't seem like the right place to suggest that?)
The proposal has been updated to allow attributes to affect module loading. As such, hosts could implement attributes such as:
import "fs" with { cjsDefaultInterop: "module.exports" }
import "fs" with { cjsDefaultInterop: "exports.default" }
Thanks for contributing to the discussion!
Currently, there are two types of ES Module implementations (as far as I'm aware):
Tools like NW.js currently have an issue, whereby it is possible to use ESM in the browser context (because it wraps Chromium, so it comes for free with browser-based ESM).
However, to import a Node modules in NW.js, one is required to
require
(hehe) any Node module that they want to import.For example:
The NW.js user can not use
import
to import Node modules.Probably a similar issues exists with Electron.
So what I'm thinking is maybe there can be a way to disambiguate between module implementations using import attributes. Then it would be possible to patch a browser context engine (f.e. Chromium), to allow things like this using an official syntax:
Of course, the naming (
with
,type
,node-esm
) is from a shed full of bikes to choose from.The alternative for a project like NW.js would be that it would need to patch the browser engine to make it so if it encounters an identifier like
fs
, it will delegate to Node ESM for that, otherwise follow the code path of normal browser-based ESM.