newrelic / node-newrelic

New Relic Node.js agent code base. Developers are welcome to create pull requests here, please see our contributing guidelines. For New Relic technical support, please go to http://support.newrelic.com.
Apache License 2.0
964 stars 391 forks source link

Error [ERR_REQUIRE_ESM]: require() of ES Module #2275

Closed jainritik closed 1 month ago

jainritik commented 1 month ago

Description

Still facing same issue( https://github.com/newrelic/node-newrelic/issues/553 ): New Relic for Node.js is disabled due to an error:

Error [ERR_REQUIRE_ESM]: require() of ES Module /Users/abc/Desktop/AA/repo-name/config/index.js from /Users/abc/Desktop/AA/repo-name/newrelic.cjs not supported.
Instead change the require of index.js in/Users/abc/Desktop/AA/repo-name/newrelic.cjs to a dynamic import() which is available in all CommonJS modules.

newrelic.cjs file:

const envConfig  = require('./config/index.js'); // for initializing environment variables

const config = {
  app_name: ["newRelic_test"],
  license_key: envConfig.NEWRELIC_LICENSE_KEY,
};
module.exports = {config}

console.log(JSON.stringify(config));

once client is created I have imported newrelic in the start of app as following: import 'newrelic';

Can you please help me in this @bizob2828 I tried multiple workarounds as well like trying to use .js file @coreyarnold @solocommand @jedashford @drmrbrewer @bizob2828

workato-integration[bot] commented 1 month ago

https://new-relic.atlassian.net/browse/NR-280808

jsumners-nr commented 1 month ago

Please review the error message. It is stating that you are are using the require function to load an ESM script, which is not possible. In other words, your ./config/index.js is ESM and you are trying to use require to load it.

jainritik commented 1 month ago

Hi @jsumners-nr , Thanks for your reply even I tried to change from require to import still facing issue: code that i am following:

const envConfig  = await import('./config/index.js');

const config = {
  app_name: ["newrelic_test"],
  license_key: envConfig.NEWRELIC_LICENSE_KEY,
};
module.exports = {config}

console.log(JSON.stringify(config));

Error:

New Relic for Node.js was unable to bootstrap itself due to an error:
Error: New Relic requires that you name this application!
Set app_name in your newrelic.js or newrelic.cjs file or set environment variable
NEW_RELIC_APP_NAME. Not starting!
    at createAgent (/Users/ritikjain/Desktop/BB/repo-name/node_modules/newrelic/index.js:160:11)
    at initialize (/Users/ritikjain/Desktop/BB/repo-name/node_modules/newrelic/index.js:105:15)
    at Object.<anonymous> (/Users/ritikjain/Desktop/BB/repo-name/node_modules/newrelic/index.js:39:3)

I tried multiple workaround but nothing worked. I would highly appreciate your help in this. Thanks.

jsumners-nr commented 1 month ago

👋 thank you for the report. Please provide a minimal reproducible example. Doing so will help us diagnose the issue. It should be the bare minimum code needed to trigger the issue, and easily runnable without any changes or extra code.

You may use a GitHub repository to host the code if it is too much to fit into a code block (or two).

jainritik commented 1 month ago

Description

Facing error while trying to integrate newRelic in nodejs. Using ES syntax.

Expected Behavior

Shoule be up and running as it is running in other repos where I am using commonJS

Steps to Reproduce

1.) Added "type": "module" in package.json 2.) Created newrelic.cjs file in root dir as written as the following code:

        const envConfig  = await import('./config/index.js');
        const config = {
          app_name: ["test_newrelic"],
          license_key: envConfig.NEWRELIC_LICENSE_KEY,
        };
        module.exports = {config}
        console.log(JSON.stringify(config));

3.) a.) Attempting to load New Relic in the app start file before loading environment variables from the config is problematic because step 2 involves importing envConfig.

import dotenv from 'dotenv/config.js'; // for initializing environment variables
import 'newrelic';

b.)Attempted to load the newrelic.cjs file created in the following manner:

import dotenv from 'dotenv/config.js'; // for initializing environment variables
import  '../newrelic.cjs'

4.) Upon executing the command npm start, the following error is encountered:

New Relic for Node.js was unable to bootstrap itself due to an error:
Error: New Relic requires that you name this application!
Set app_name in your newrelic.js or newrelic.cjs file or set environment variable
NEW_RELIC_APP_NAME. Not starting!
    at createAgent (/Users/ritikjain/Desktop/BB/RepoName/node_modules/newrelic/index.js:160:11)
    at initialize (/Users/ritikjain/Desktop/BB/RepoNamenode_modules/newrelic/index.js:105:15)
    at Object.<anonymous> (/Users/ritikjain/Desktop/BB/RepoName/node_modules/newrelic/index.js:39:3)
    at Module._compile (node:internal/modules/cjs/loader:1358:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1416:10)
    at Module.load (node:internal/modules/cjs/loader:1208:32)
    at Module._load (node:internal/modules/cjs/loader:1024:12)
    at cjsLoader (node:internal/modules/esm/translators:348:17)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/translators:297:7)
    at ModuleJob.run (node:internal/modules/esm/module_job:222:25)

Your Environment

Env: Node version: v20.13.1

Additional context

Workaround that i tried: a.) tried to import the modules dynamically using async and await but didn't work. b.) Followed this doc https://docs.newrelic.com/docs/apm/agents/nodejs-agent/installation-configuration/es-modules/ but didn't work.

@jsumners-nr Let me know if you need anything else from my side.

jsumners-nr commented 1 month ago

The linked documentation, specifically the section regarding the configuration file https://docs.newrelic.com/docs/apm/agents/nodejs-agent/installation-configuration/es-modules/#configuration, clearly highlights that we only support CommonJS modules for configuration files. Due to the way ES modules are loaded by Node.js at this time, it is not possible to mix a CommonJS configuration with other files written as ESM.

The only possible way to do so would be to do something like:

// newrelic.cjs

main().then(() => {}).catch(console.error)

async function main() {
  const config = await import('./config.js')
  module.exports.config = {
    app_name: [config.app_name],
    license_key: 'invalid'
  }
}

But that will not work because, as stated in the linked documentation, we use require to load the configuration file: https://github.com/newrelic/node-newrelic/blob/07a841b9acf0a0dcb1a495c5cb0ee8f77e283fc9/lib/config/index.js#L1700-L1702

You can still read environment variables in your newrelic.cjs:

'use strict'

require('dotenv').config()

module.exports.config = {
  app_name: [process.env.MY_COOL_APP_NAME],
  license: process.env.MY_LICENSE_KEY
}
bizob2828 commented 1 month ago

@jainritik you also don't need to load alternative configurations and assign in a file. All of our configurations support environment variable equivalents and it is documented here. so if you just specify NEW_RELIC_LICENSE_KEY and NEW_RELIC_APP_NAME as env vars you won't need a newrelic.cjs

jainritik commented 1 month ago

@bizob2828 @jsumners-nr So actually from config I am trying to get NEW_RELIC_LICENSE_KEY, NEW_RELIC_APP_NAME on the basis of env. If env == 'development' then it would go to development.js file and if env == 'production' then it would go to production.js file and will pick the params(NEW_RELIC_LICENSE_KEY, NEW_RELIC_APP_NAME).

File structure config

newrelic.ejs and config are in root dir.

index.js

import devConfig from './development.js';
import qaConfig from './qa.js';
import prodConfig from './production.js';
let config;
switch (process.env.NODE_ENV) {
    case 'production':
        config = prodConfig;
        break;
    case 'developement':
        config = devConfig;
        break;
    default:
        config = qaConfig
}

export default config;

newrelic.cjs

'use strict'

require('dotenv')
console.log("***********", process.env.NEWRELIC_APP_NAME_DEV, process.env.NEWRELIC_LICENSE_KEY)
module.exports.config = {
  app_name: [process.env.NEWRELIC_APP_NAME_DEV],
  license: process.env.NEWRELIC_LICENSE_KEY
}

this is what I am trying to do. Still getting some errors


*********** testName testPwd
New Relic for Node.js halted startup due to an error:
Error: Not starting without license key!
    at onNextTick (/Users/ritikjain/Desktop/BB/bb-skillpolls-api/node_modules/newrelic/lib/agent.js:262:16)
    at process.processTicksAndRejections (node:internal/process/task_queues:77:11)
jsumners-nr commented 1 month ago

I recommend reviewing https://blog.platformatic.dev/handling-environment-variables-in-nodejs and paying particular attention to the discussion around NODE_ENV. I also recommend simply using our documented environment variables for your use case. According to the information in this issue, it looks like you do not need any newrelic.cjs file if you set the requisite environment variables.

Other than that, this seems to be out of scope, and is not a bug. Everything is working as intended, and the issue is application structure.