Replies: 79 comments 155 replies
This comment has been hidden.
This comment has been hidden.
-
I vaguely recall a |
Beta Was this translation helpful? Give feedback.
-
Further discussion from the modules repo nodejs/modules#296 I found two more issues, I think it's better to wait for someone who was active at the modules team to say what ended up happening that caused Edit: found it #27184 Edit2: found the reasoning nodejs/modules#300 (comment) |
Beta Was this translation helpful? Give feedback.
-
Thanks for helping me find those links. I completely disagree with the reasoning stated there (I don't care if it was "package-type" or "entry-type", just would want some way to do it)... but I don't have the energy to try to re-litigate it. |
Beta Was this translation helpful? Give feedback.
-
@getify, those decisions aren't etched in stone. We may be able to accommodate you especially if you would be interested in making a pull request. Having a flag as you describe does seem useful to me. |
Beta Was this translation helpful? Give feedback.
-
If you're writing a file that has no associated package.json, how would you expect to convey (for invocations beyond the current one) the parse goal of the file beyond the extension, given that |
Beta Was this translation helpful? Give feedback.
-
Would there be a problem if we added a flag that allows the user to change the default behaviour ? |
Beta Was this translation helpful? Give feedback.
-
@targos it would encourage people to use a file extension that doesn’t match the parse goal of their file, without an accompanying package.json to carry that information. |
Beta Was this translation helpful? Give feedback.
-
one more time: this is not a module import {random} from 'library';
console.log(random()); the fact All main bundles/files on the Web also are not modules: these are programs, that use a module system, yes, but these are not modules. index.mjs is not a module, if it doesn't export a thing, is a program. But yeah, this has been discussed for ages already. |
Beta Was this translation helpful? Give feedback.
-
Last one, for correctness, and completeness, sake: <script type="module" src="program.js"> The type there doesn't practically define the parsing goal, it defines the module system, and it propagates with it, because Something like: node --type=module --force-type=true program.js could enforce the module system and its propagation, so that by default everything imported by program.js would have a module system, by default, that is ESM, not CommonJS. That's how you could define the parsing goal, but there's never been interest in doing this, although tons of developers keep asking for this, so I wish this common request was more welcomed, or developers expectations acknowledged.
'cause this is sad, but from personal experience, also true ... current state is more opinionated than concrete, imho, while competitors factor out this gotcha for developers (see deno). edit node --default-type=module program.js
node --input-type=module --override-default-input-type=true all variants that could make it, if there was the will to do so. |
Beta Was this translation helpful? Give feedback.
-
BackgroundI built a tool called moduloze that converts a tree of commonjs-style files to either UMD or ESM style files. It's designed either to be used as a one-time codemod for code authors wishing to permanently convert to ESM, or (my use) for package authors who still prefer to write in commonjs but who want to distribute also in UMD and ESM formats for wider consumption flexibility. I have all my main/active npm packages using it. Along with that, I also have a tool called import-remap which allows you to apply import-map style rewriting of your import specifiers as a build-tool (instead of runtime aliasing). I also use import-remap in some of my projects to modify the output from moduloze to be ESM that's more readily useable in the browser. So, taken together, these two tools give authors a narrower-focused, and more flexible/less opinionated path (than, say, typical all-in-one bundlers) for supporting code that's CJS, UMD, and ESM, at the discretion of the users of my tools. Note: It is not a goal to interop between formats, but to support building parallel trees of code for each format. In that spirit, these tools (moduloze particularly) allow you to specify that you want your built ESM modules to be either .mjs or .js file extension. I offer that choice because I don't want my opinions on that topic to limit others. If they choose to make .js files with ESM code in them, they are responsible to either use that code in an environment like the browser where the script tag conveys the format, or in Node with some supporting configuration (e.g., a package.json). Use-CaseI would like to be able to test the various combinations of outputs from my tools (both automated test suites, and user-opt-in verification steps when the tools are used on user-code). I find it annoying/inconvenient to have to create a stub package.json file in a directory of built ESM-containing .js files with nothing but It's mildly annoying to need it for my tool test suite, but it's especially annoying for the opt-in at-use-time verifications performed on user-code the tool just outputted, since such a file has to be created just to invoke Node then deleted right after... every time. I would strongly prefer to have a flag like I've read all the linked threads (and comments here) and I'm aware of the objections to such a feature -- i.e., general users can't/shouldn't be trusted with such a feature. I disagree with these assertions, but don't need to have them repeated here, and I don't care to re-debate it. I've stated my use-case for posterity sake. I'll leave it at that, as I suspect it won't sway the strong opinions held by some in charge of Node's direction with modules. |
Beta Was this translation helpful? Give feedback.
-
FWIW,
It'd be great if this issue would be re-considered/opened (among others) instead of keep hearing, here and there, alternatives are much better, so thanks in advance for considering this. |
Beta Was this translation helpful? Give feedback.
-
II think the discussion would be more productive if there were a PR implementing such a flag. Let's reopen to see if there are volunteers to work on that. |
Beta Was this translation helpful? Give feedback.
-
FWIW I think the ask here is pretty reasonable. @ljharb given the use case and the suggestion (a |
Beta Was this translation helpful? Give feedback.
-
@benjamingr Personally, I think |
Beta Was this translation helpful? Give feedback.
-
So is there any way to force set type to module with some command line argument in node? I've filled a related issue #41136 describing the problem with creating one-file scripts on node.js, and the major problem is absence of ability to set file type to module, using cli argument, using shebang. Will be good to have something like this: #!/usr/bin/env -S node --package-type=module
import fs from 'fs';
import util from 'util';
const readdir = util.promisify(fs.readdir);
let result = await readdir('.');
console.log(result); |
Beta Was this translation helpful? Give feedback.
-
As a workaround, I'm using esm-ts-node. This is not the answer to your question, but I was looking for the same kind of option and found your issue. Maybe this can help. |
Beta Was this translation helpful? Give feedback.
-
An interesting additional use-case for this flag from @rauschma: when you want to force a file to be treated as ESM when the file has no file extension, like typical *nix CLI tools look. |
Beta Was this translation helpful? Give feedback.
-
to provide an update on this, with the current state of the --experimental-loader=loader.js api i was able to provide a loader.js that relies on the default resolve() hook's determination of "commonjs" modules before entering the load() hook, where it attempts to load them as es modules if a tentative commonjs resolution (with createRequire) fails due to module-related syntax error, by overwriting the determined context.format key. getify's concern for undeterministic "format" keys due to lack of file extension or require- or unix-like extensionless specifiers can be solved by additionally returning the source text in a "code" field and shortCircuit to prevent the failure of the default hook (if(!/.js$/.test(url))return {code:read(url+".js"),shortCircuit:true};). The tentative require only to verify commonjs may be expensive, but this is used in scenarios where commonjs is not favored anyway. The module-like syntaxerror verification could also be elaborated, i have only encountered "cannot use import outside a module" and "invalid token 'export'" errors when writing this. my use case has been importing unbuilt package source codes written in inaccessible es, with their package.json only specifying the to-be-built target's type, and the source's syntax only being implied in rollup configs (eg. acorn, but source syntax is commonly encrypted in various inscrutible build configs nowadays). the justification to do this was a bundling tool that relies on acorn, but capable of building acorn itself (in which case acorn is not readily available, and automatically building it - as possibly any other package - seemed more difficult and expensive to fathom than just expecting its source to be coherent before it's bundled). the use case may be debated, but it's not strictly relevant to the subject issue. import {createRequire} from "module";
const require=createRequire(import.meta.url);
export function load(url,context,next)
{if(context.format==="commonjs")
await require(url).catch(fail=>
{let syntax=fail.constructor.name==="SyntaxError";
if(syntax&&["import","export"].some(token=>RegExp(token).test(fail.message))
return Object.assign(context,{format:"module"});
throw fail;
});
return next(url,context);
}); |
Beta Was this translation helpful? Give feedback.
-
maybe we could align with the new web-modules api it is implemented already for wasm https://github.com/lemanschik/wasm-component-system/blob/main/README.md it implements a wasm component system on sharedMemory i want to do the same for nodeJs in general to get easyer Interop between nodeJs and our existing browser components. nodejs got invented as chromium got no component system this changed the last years. now it would be time that nodejs adopt the chromium patterns. as it is based on chromium and not chromium based on NodeJS The WebAssembly.instantiate Streaming() function compiles and instantiates a WebAssembly module directly from a streamed underlying source. This is the most efficient, optimized way to load wasm code. And so is also true for ESM this handels load via fetch and instantiation the so called load async independent code able with the stream interface to prevent users from writing locking logic and queues. they include error propagation and back pressure and all that. As also none documented hardware clocking scheduling algorithms in experimental state to sync clock execution cross cluster of modules on web scale size. Mini Exampleconst wasmModuleBasedInputSource = new ReadableStream({ start: async ({ enqueue: imported_func }) => (await WebAssembly
.instantiateStreaming(fetch("simple.wasm"),
{ imports: { imported_func } }) ).instance.exports.exported_func() }); so put instantion into userland! this way the user of the runtime gets loader feedback as he does in the browser if he wants to but can also simply ignore that. this is adaptable. only action able itm is to add a extra api to your fetch implementation that does module instantiation in userland. already using working workaround polyfill via import data url in nodejs and blob in the browser to create reference able memory for the result that is reusable cross module system in general fetch and import already supply everything but the user is not aware of what he is doing. import returns in fact instance.exports already. but the user is not aware that this is a reusable sharedMemory reference. with a loader api like the WASM one expressed maybe as await ESModule.instantiateStreaming(fetch) could shape the mind set of the user into the right directions. |
Beta Was this translation helpful? Give feedback.
-
It is not possible to specify the module type using a command-line parameter when running a Node.js program. The module type is determined by the file extension of the imported module. For example, if a file has a .js extension, it will be treated as a CommonJS module. If it has a .mjs extension, it will be treated as an ECMAScript module. If you want to force a specific module type for all imports in your program, you can use the --input-type flag when running the program with the node command. For example: This will treat all imports in the index.js file as ECMAScript modules, regardless of the file extension. Note that this flag only affects the entry point file specified on the command line, and not any imported modules. Alternatively, you can specify the "type" field in the "main" field of your package.json file to specify the module type for the entry point of your program. |
Beta Was this translation helpful? Give feedback.
-
as long as electron is not esm ready, its pretty bad to be left without the options. |
Beta Was this translation helpful? Give feedback.
-
Having similar issues with two different projects, one based on serverless-framework serverless offline, which doesn't seem to like setting "type":"module, and Jasmine 4 which basically requires it. It would be nice to set the module type in CLI only for Jasmine so I can run my tests. Until its all ESM I have to manually add "type":"module" to package.json for tests and remove it when tests are done. |
Beta Was this translation helpful? Give feedback.
-
Hitting this because we have systems that (by default) install some lower level dependencies into a directory that isn't Ideally settings originating from the |
Beta Was this translation helpful? Give feedback.
-
Hello great community of node.js. I think this ticket represents what is wrong with node.js - failure to observe backwards compatibility on language level (why I should ever need to specify what level of JS spec I am using with latest version of node?) and failing developers at the same time to force node.js to accept specific library and or script at specific language level. (yes, I know that I can put a package.json with override of language level after installing a package but, this is beyond pale. But completely consistent with how npm should not be used. Now I think that node.js can only be used by small home projects and should not be treated seriously) |
Beta Was this translation helpful? Give feedback.
-
Out of my view the only current solution that works well for electron and node js is bundling or usage of a loader. Thats true for nodejs and for electron. The most solid solution is the usage of rollup with with CJS support then loading it as CJS or bundle it as CJS Modules are great as Author format but not as execution format. That rule stays. |
Beta Was this translation helpful? Give feedback.
-
my only humble wish is to not have to carry a package.json along with my module to be able to load it. Modules are the standard ES syntax, so Node.js should be able to assume that at least with a flag, if not by default. I have figured out a solution with a --loader module to load dependency source files from folders where the package.json specifies the format of the transpiled (therefore in a clean repo clone nonexistent) commonjs, and not those ESM source files by falling back to context.type="module" in case of that sort of error. But the problem begins at the fact that i wrote that --loader module in the current standard ESM format, and i have no means to use That itself without a silly package.json tagging along only to specify {"type": "module"}. Which is, mind you, the standard format, in case i haven't mentioned it yet. |
Beta Was this translation helpful? Give feedback.
-
This is now possible #50096 🎉 cc @getify (well, that and |
Beta Was this translation helpful? Give feedback.
-
@benjamingr you should also mention the more importent flag: https://nodejs.org/dist/latest-v21.x/docs/api/cli.html#--experimental-detect-module the --experimental-detect-module simple uses the same that typescript uses in classic resolve so both systems would have same behavior. |
Beta Was this translation helpful? Give feedback.
-
Hope |
Beta Was this translation helpful? Give feedback.
-
I'm aware that I can name a file with
.mjs
or set"type": "module"
in package.json. I'm also aware of the--input-type=module
CLI parameter.What I'm not understanding is, why isn't there a way to pass a parameter flag to force module interpretation for the
.js
file I specify? Was there a reason that--input-type
can only be used with string input and not to control module interpretation of a.js
file?I tried searching old issues to find this discussed but my searching failed me. I feel certain it must have been intentionally omitted, but I'm just trying to understand why?
Beta Was this translation helpful? Give feedback.
All reactions