Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove --experimental-loader ExperimentalWarning as the option doesn't exist anymore / is no longer experimental #51196

Open
cuuupid opened this issue Dec 17, 2023 · 14 comments

Comments

@cuuupid
Copy link

cuuupid commented Dec 17, 2023

Version

21.4.0

Platform

MacOS Sonoma

Subsystem

No response

What steps will reproduce the bug?

Using --loader (not --experimental-loader)

How often does it reproduce? Is there a required condition?

Always

What is the expected behavior? Why is that the expected behavior?

This feature is clearly no longer experimental (ESM has been out for years, is the default for many new projects, and the option is no longer --experimental-loader but --loader). Since it generates an ExperimentalWarning and specifically logs --experimental-loader I'm almost certain this is just an oversight.

What do you see instead?

(node:82007) ExperimentalWarning: `--experimental-loader` may be removed in the future; instead use `register()`:
--import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register("./loader.js", pathToFileURL("./"));'

Additional information

Was previously discussed in #30213 and there were plans to merge a fix for this in 2019, but seems the discussion was closed and died out. Opening a new issue for visibility (and also since the error/basis is slightly different).

@aduh95
Copy link
Contributor

aduh95 commented Dec 18, 2023

#30213 is about --experimental-modules, not --experimental-loader--experimental-modules was the flag used to enable ESM at the time it was still experimental. ESM has since been unflagged, and is no longer experimental.

On the other hand, --experimental-loader is a different flag, still very much experimental. The --loader alias is undocumented, and not recommended for use. As the warning suggests, it's unclear whether this flag is going to stay for much longer, as it stands it seems that Module.register covers all of the use cases (but it's not a done deal, if someone brings a good use case for --experimental-loader, it can stay).

@cuuupid
Copy link
Author

cuuupid commented Dec 19, 2023

While #30213 was opened for experimental modules it seems it became inclusive of experimental loaders midway through, but can understand that sentiment has shifted since then.

I'd defend not removing the --loader flag altogether very, very strongly as it's still widely used by TypeScript projects and is the most viable way to use ts-node, esm, and Node 20+ in combination (as these do not normally play well together). I'm aware ts-node is a disjoint project outside the purview of Node.js, but it would still impact a large portion of the community. Some issue tracking here: TypeStrong/ts-node#1997

Instead, as Module.register moves to stable, could --loader be accelerated directly to legacy? module.register is a better alternative to --loader, but there are not currently better alternatives using module.register to popular loaders using --loader. Allowing the two to coexist for some time would allow the community to shim their way to parity.

@aduh95
Copy link
Contributor

aduh95 commented Dec 19, 2023

but there are not currently better alternatives using module.register to popular loaders using --loader

What about the flag suggested in the warning though, the one you pasted above? It should be a drop-in replacement.

@listvin
Copy link

listvin commented Jan 10, 2024

@aduh95, can you please elaborate on how to apply suggested solution? I do not understand where I should put these line.
Currently I am starting my project as node --loader ts-node/esm ./src/index.ts
Warning is the same, nodejs 20, module == moduleResolution == "Node16", no frontend

@aduh95
Copy link
Contributor

aduh95 commented Jan 10, 2024

As the warning suggests, you should replace the --loader ts-node/esm flag with the one suggested in the warning, and the warning will disappear. FWIW there's an open issue on the ts-node repo to allow users to use a simpler syntax: TypeStrong/ts-node#2072

@Enteleform
Copy link

Enteleform commented Feb 3, 2024

@aduh95

as it stands it seems that Module.register covers all of the use cases (but it's not a done deal, if someone brings a good use case for --experimental-loader, it can stay).

What about the flag suggested in the warning though, the one you pasted above? It should be a drop-in replacement.

The implementation suggested in the warning is more than just a flag, it's an entire inline script:

--import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register("./loader.js", pathToFileURL("./"));'

This is unergonomic and reduces the readability of package scripts by pulling implementation details into what should be a high-level orchestration of commands.

The alternative of moving the inline script into an actual file indeed improves the readability of package scripts, at the expense of creating an unnecessary boilerplate file which will likely be duplicated across many projects.

Several issues have been opened related to this matter, and the typical suggestion of stabilizing the --loader flag and removing the warning solves this common use case in a more elegant and concise way than either of the aforementioned workarounds.

@aduh95
Copy link
Contributor

aduh95 commented Feb 3, 2024

Several issues have been opened related to this matter

If you want to make a stronger case, I'd suggest linking to those issues.

The alternative of moving the inline script into an actual file indeed improves the readability of package scripts, at the expense of creating an unnecessary boilerplate file which will likely be duplicated across many projects.

I think the idea is that most packages that want to hook into the module resolution would probably need communication with the main thread – and so, it would not be an "unnecessary boilerplate file", but a file containing the main thread logic as well as the actual Module.register call and setting up the communication channel. (N.B. it's still possible to do cross-thread communication with --loader, but with a worse DX.)
If your use case is a loader that doesn't need any cross-thread communication, I totally understand that it's frustrating not to use the --experimental-loader flag (in fact, Node.js tests contains a bunch of tests that are still using that flag, because it's simply more convenient indeed). But how niche is that use-case? I don't know, if that's you, you should definitely speak up so @nodejs/loaders are aware of it.

@ttodua
Copy link

ttodua commented Feb 7, 2024

Working command:

node  --import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register("ts-node/esm", pathToFileURL("./"));'   ./path/to/your_file.ts

if you want to add into VSCODE's launch.json for debugging, you can use:

{
    "version": "0.2.0",
    "configurations": [
       {
            "name": "run selected TS file",
            "type": "node",
            "request": "launch",
            "localRoot": "${workspaceFolder}",
            "runtimeArgs": [
                "--import", 
                "data:text/javascript,import { register } from \"node:module\"; import { pathToFileURL } from \"node:url\"; register(\"ts-node/esm\", pathToFileURL(\"./\"));"
            ],
            "args": ["${file}"],
            "console": "integratedTerminal",
            "skipFiles": ["<node_internals>/**", "node_modules/**"],
        }
   ]
}

@edukisto
Copy link

The --loader/--experimental-loader flag

NODE_OPTIONS="--experimental-loader ts-node/esm" npx webpack configtest

offers a solution

ExperimentalWarning: `--experimental-loader` may be removed in the future; instead use `register()`:
--import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register("ts-node/esm", pathToFileURL("./"));'

To make the command more ergonomic, create a file that registers module resolution hooks. Let’s name the file register.js.

import { register } from 'node:module';
import { pathToFileURL } from 'node:url';

register('ts-node/esm', pathToFileURL('./'));

Then use the --import flag to import the file.

NODE_OPTIONS="--import=./register.js" npx webpack configtest

Node.js v20.9, v20.10, v20.11 (LTS: Iron).

@skagedal
Copy link

skagedal commented May 1, 2024

I'd like to mention here that the "getting started" documentation page Node.js with Typescript simply says:

Since Node.js v19.0.0, you can use a custom loader. Download a loader such as ts-node or tsx or nodejs-loaders
First you need to install the loader:
npm i -D ts-node
Then you can run your TypeScript code like this:
node --loader=ts-node/esm example.ts

No mention of this being experimental or planned for removal. So it doesn't seem quite the case as @aduh95 was saying earlier in the thread:

The --loader alias is undocumented, and not recommended for use.

Is this just a documentation bug that should be fixed?

@skagedal
Copy link

skagedal commented May 1, 2024

I also see the --loader option in node --help. (On Node v22.0.0)

@GeoffreyBooth
Copy link
Member

GeoffreyBooth commented May 1, 2024

Is this just a documentation bug that should be fixed?

Yes, the documentation should be using --import instead. I posted TypeStrong/ts-node#1909 (comment) to encourage ts-node to update.

I also see the --loader option in node –help. (On Node v22.0.0)

Technically it exists, even though it was created by accident. I still think we’re likely to remove it in the future, but until we do, node --help will probably list it as it would be incorrect to leave out a flag that’s supported.

@josh-hemphill
Copy link

One thing I ran into was that you can't use quotes if you set the --import flag in node_options under .npmrc. I was eventually able to get it working after url-encoding the whole string, doesn't quite seem like a bug, but it's quite a pain:

node-options=--import data:text/javascript,import%20%7B%20register%20%7D%20from%20%22node%3Amodule%22%3Bimport%20%7B%20pathToFileURL%20%7D%20from%20%22node%3Aurl%22%3Bregister%28%22ts-node%2Fesm%22%2C%20pathToFileURL%28%22.%2F%22%29%29%3B

@ttodua
Copy link

ttodua commented May 24, 2024

if this benefits others, i advise to try tsx instead of ts-node. Either run directly tsx file.ts or with '--import', 'tsx' arguments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants