nodejs / help

:sparkles: Need help with Node.js? File an Issue here. :rocket:
1.45k stars 278 forks source link

createRequire - can't figure out or it's a bug #4229

Closed Mozzart88 closed 2 months ago

Mozzart88 commented 1 year ago

Details

Hello! For a testing purposes I need to dynamically load and unload modules. My solution is looks like this

import { test } from 'node:test';
import assert from 'node:assert';
import { createRequire } from 'node:module';
import path from 'node:path';

const require = createRequire(import.meta.url);
function clearModule(id, src) {
    const module = require.cache[require.resolve(id)];
    const root = path.parse(path.resolve(src)).dir;
    if (module && 'children' in module && module.children.length > 0) {
        for (const child of module.children) {
            if (child.loaded && child.path.includes(root))
                clearModule(child.filename, src);
        }
    }
    console.log(module);
    delete require.cache[require.resolve(id)];
}

function requireModule(id) {
    return require(id);
}

This usage is documented here

And it works fine with tsx, but not with node. With node it throws an exception ERR_REQUIRE_ESM with this message:

require() of ES Module /app/build/src/app.js from /app/build/tests/unit/app.test.js not supported.
    Instead change the require of app.js in /app/build/tests/unit/app.test.js to a dynamic import() which is available in all CommonJS modules.

Node.js version

v 18.15 v 20.15.0

Example code

No response

Operating system

MacOS Ventura 13.4.1 and on docker

Scope

code, runtime, meta (don't really understand this question)

Module and version

node:module

preveen-stack commented 1 year ago

cc @nodejs/loaders

aduh95 commented 1 year ago

It's not a bug, requireing ES modules is not possible, you need to use import(). Clearing loaded ES modules is also not possible because the ECMAScript spec does not define any way to clear modules.

You could load several instances of the same module by using query string, e.g. import('./file.js') and import('./file.js?test=0') would load two module instances of the same file.js file.

Mozzart88 commented 1 year ago

Great, Thnx! But I still don't understand the usage of the createRequire function - if require is not possible in ES, then why do we need this function and how should we use it?

aduh95 commented 12 months ago

createRequire is provided as an escape mecanism for apps that relies upon a legacy feature of the CJS loader. It's not meant to be used unless you have no other choice.

Mozzart88 commented 12 months ago

Ok, but it's not working properly. Or did I use it incorrectly? In my case, it just throws an error.

github-actions[bot] commented 3 months ago

It seems there has been no activity on this issue for a while, and it is being closed in 30 days. If you believe this issue should remain open, please leave a comment. If you need further assistance or have questions, you can also search for similar issues on Stack Overflow. Make sure to look at the README file for the most updated links.

github-actions[bot] commented 2 months ago

It seems there has been no activity on this issue for a while, and it is being closed. If you believe this issue should remain open, please leave a comment. If you need further assistance or have questions, you can also search for similar issues on Stack Overflow. Make sure to look at the README file for the most updated links.