Search code examples
javascriptnode.jsnode-modules

require() not working in module type nodejs script


In my package.json file I've specified that my nodejs app is of type module, because if I do not do that, it seems that I can not use import statements. This is how it looks like now:

{
  "name": "...",
  "version": "1.0.0",
  "description": "....",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "...."
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "lodash": "^4.17.15"
  },
  "type": "module"
}

But if I add the "type": "module" to my package.json file, I can't use require statements anymore, because I get a ReferenceError: require is not defined error.

If I remove the "type": "module" line from package.json, and rewrite all of my imports to requires, everything works without an error.

I can't seem to find any indication, that import and require can not be mixed or used together in the same script, am I missing something here, or I am having some other bug? How could I resolve to use these two kind of statements in the same script?

Why I would need this, is because I want to require some config files based on dynamic paths, and only if the files exists, which I think I can not do with import.

DISCLAIMER: I am rather new to nodejs server side programming, so it is possible that I am approaching this situation very wrongly, if that's the case, please advice me something, based on the Why I've mentioned above.

NOTE: I am running this node script from the server terminal, and not from the browser.


Solution

  • But if I add the "type": "module" to my package.json file, I can't use require statements anymore, because I get a ReferenceError: require is not defined error.

    Right. It's either/or. Either you use ESM (JavaScript modules, type = "module") or you use CJS (CommonJS-like Node.js native modules, require).

    But there is some interoperability between them. For instance, in an ESM module you can import CJS modules, and you can use createRequire to create a require function to use to load CJS modules.

    Why I would need this, is because I want to require some config files based on dynamic paths, and only if the files exists, which I think I can not do with import.

    You can still do that while using type="module". You have a few options:

    1. If these "config" files are JavaScript, you can use createRequire:

      import { createRequire } from "module";
      const require = createRequire(import.meta.url);
      const yourData = require("./config.js");
      
    2. If these config files are JSON, you can use the currently-experimental support for importing JSON modules. Since you said you want to allow for files not existing, you'd want to use dynamic import() rather than static import declarations:

      let config = /*...defaults...*/;
      try {
          config = await import("./config.json", { assert: { type: "json" } });
      } catch (error) {
          // ...the file didn't exist or wasn't valid JSON...
      }
      
    3. Or if (again) they're JSON, you can go old school: use readFile and JSON.parse. :-)