Keywords: Node.js | ERR_REQUIRE_ESM | Module Compatibility
Abstract: This paper provides an in-depth analysis of the ERR_REQUIRE_ESM error commonly encountered in Node.js environments, focusing on compatibility issues during the transition of node-fetch from CommonJS to ES modules. By comparing two primary solutions—downgrading package versions and using dynamic imports—the article explains module system differences, package version management strategies, and appropriate use cases for dynamic import(). Detailed code examples and step-by-step instructions help developers understand fundamental differences in module loading mechanisms, with best practice recommendations for various Node.js versions.
Problem Background and Error Analysis
During Node.js development, attempting to load ES modules using the require() function results in an ERR_REQUIRE_ESM error. This typically occurs when npm packages transition from CommonJS to ES module specifications. The error message explicitly states: require() of ES Module [...] is not supported. Instead change the require of index.js to a dynamic import() which is available in all CommonJS modules.
From a technical perspective, this error stems from Node.js's module loading mechanism. CommonJS uses synchronous require() functions, while ES modules employ asynchronous import statements. When package authors convert packages from CommonJS to ES modules, existing require() calls can no longer correctly load the new module format.
Core Solution: Version Downgrading Strategy
To address the issue where the latest version of node-fetch only supports ES modules, the most straightforward solution is to downgrade to an older version compatible with CommonJS. Versions node-fetch@2.6.1 and below maintain the CommonJS format, ensuring seamless compatibility with existing require() calls.
Execute the following command to install the specified version:
npm install node-fetch@2.6.1This approach offers the advantage of requiring no modifications to existing code logic, preserving project stability and consistency. For developers learning or maintaining existing projects, this represents the safest and quickest resolution method.
Alternative Approach: Dynamic Import Technology
Beyond version downgrading, dynamic import() functions can be employed to load ES modules. Dynamic imports are part of the ECMAScript standard and are fully available within Node.js's CommonJS modules.
Replace the original require call with:
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));This method allows continued use of the package's latest version, providing access to recent features and security updates. However, note that dynamic imports return Promise objects and must be used within asynchronous contexts.
Code Examples and Implementation Details
Below is a complete code example applying the version downgrading solution in an NFT project context:
const FormData = require('form-data');
const fetch = require('node-fetch'); // Using version 2.6.1
const path = require("path");
const basePath = process.cwd();
const fs = require("fs");
fs.readdirSync(`${basePath}/build/images`).forEach(file => {
const formData = new FormData();
const fileStream = fs.createReadStream(`${basePath}/build/images/${file}`);
formData.append('file', fileStream);
let url = 'https://api.nftport.xyz/v0/files';
let options = {
method: 'POST',
headers: {
Authorization: '[...]',
},
body: formData
};
fetch(url, options)
.then(res => res.json())
.then(json => {
const fileName = path.parse(json.file_name).name;
let rawdata = fs.readFileSync(`${basePath}/build/json/${fileName}.json`);
let metaData = JSON.parse(rawdata);
metaData.file_url = json.ipfs_url;
fs.writeFileSync(`${basePath}/build/json/${fileName}.json`, JSON.stringify(metaData, null, 2));
console.log(`${json.file_name} uploaded & ${fileName}.json updated!`);
})
.catch(err => console.error('error:' + err));
});Module System Evolution and Compatibility Considerations
Node.js's module system has evolved from CommonJS to ES modules. CommonJS employs synchronous loading, suitable for server-side development; ES modules support static analysis and tree shaking, better suited for modern front-end development.
During migration, developers must consider:
- Compatibility of project dependencies
- Support level of build tools
- Team technology stack preferences
- Long-term maintenance costs
For new projects, adopting ES module specifications directly is recommended; for existing projects, choose between gradual migration or maintaining the status quo based on specific circumstances.
Best Practice Recommendations
Based on practical development experience, we recommend:
- Explicitly specify dependency version ranges in
package.jsonto avoid unexpected breaking changes - Regularly check dependency update logs to understand compatibility changes
- For critical dependencies, consider locking specific versions or using version management tools
- Establish module usage standards within teams to unify technology stacks
- Consider using tools like TypeScript to enhance type safety in module management
Through proper version management and technology selection, errors like ERR_REQUIRE_ESM can be effectively avoided, ensuring stable project operation.