The package linked to from here is now pure ESM. It cannot be require()
'd from CommonJS.
This means you have the following choices:
- Use ESM yourself. (preferred)
Useimport foo from 'foo'
instead ofconst foo = require('foo')
to import the package. Follow the below guide. - If the package is used in an async context, you could use
await import(…)
from CommonJS instead ofrequire(…)
. - Stay on the existing version of the package until you can move to ESM.
You also need to make sure you're on the latest minor version of Node.js. At minimum Node.js 12.20, 14.14, or 16.0.
I would strongly recommend moving to ESM. ESM can still import CommonJS packages, but CommonJS packages cannot import ESM packages synchronously.
ESM is natively supported by Node.js 12 and later.
You can read more about my ESM plans.
My repos are not the place to ask ESM/TypeScript/Webpack/Jest/ts-node/CRA support questions.
- Add
"type": "module"
to your package.json. - Replace
"main": "index.js"
with"exports": "./index.js"
in your package.json. - Update the
"engines"
field in package.json to Node.js 12:"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
. - Remove
'use strict';
from all JavaScript files. - Replace all
require()
/module.export
withimport
/export
. - Use only full relative file paths for imports:
import x from '.';
→import x from './index.js';
. - If you have a TypeScript type definition (for example,
index.d.ts
), update it to use ESM imports/exports. - Optional but recommended, use the
node:
protocol for imports.
Yes, but you need to convert your project to output ESM. See below.
- Add
"type": "module"
to your package.json. - Replace
"main": "index.js"
with"exports": "./index.js"
in your package.json. - Update the
"engines"
field in package.json to Node.js 12:"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
. - Add
"module": "ES2020"
to your tsconfig.json. - Use only full relative file paths for imports:
import x from '.';
→import x from './index.js';
. - Remove
namespace
usage and useexport
instead. - Optional but recommended, use the
node:
protocol for imports. - You must use a
.js
extension in relative imports even though you're importing.ts
files.
If you use ts-node
, follow this guide.
Electron doesn't yet support ESM natively.
You have the following options:
- Stay on the previous version of the package in question.
- Bundle your dependencies with Webpack into a CommonJS bundle.
- Use the
esm
package.
The problem is either Webpack or your Webpack configuration. First, ensure you are on the latest version of Webpack. Please don't open an issue on my repo. Try asking on Stack Overflow or open an issue the Webpack repo.
Next.js doesn't yet support ESM. Workaround.
Read this first. The problem is either Jest (#9771) or your Jest configuration. First, ensure you are on the latest version of Jest. Please don't open an issue on my repo. Try asking on Stack Overflow or open an issue the Jest repo.
If you have decided to make your project ESM ("type": "module"
in your package.json), make sure you have "module": "ES2020"
in your tsconfig.json and that all your import statements to local files use the .js
extension, not .ts
or no extension.
Follow this guide and ensure you are on the latest version of ts-node
.
Create React App doesn't yet fully support ESM. I would recommend opening an issue on their repo with the problem you have encountered. One known issue is #10933.
Follow this guide.
We got you covered with this ESLint rule. You should also use this rule.
import {fileURLToPath} from 'node:url';
import path from 'node:path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(fileURLToPath(import.meta.url));
However, in most cases, this is better:
import {fileURLToPath} from 'node:url';
const foo = fileURLToPath(new URL('foo.js', import.meta.url));
And many Node.js APIs accept URL directly, so you can just do this:
const foo = new URL('foo.js', import.meta.url);
There's no good way to do this yet. Not until we get ESM loader hooks. For now, this snippet can be useful:
const importFresh = async modulePath => import(`${modulePath}?x=${new Date()}`);
const chalk = (await importFresh('chalk')).default;
Note: This will cause memory leaks, so only use it for testing, not in production. Also, it will only reload the imported module, not its dependencies.
JavaScript Modules will eventually get native support for JSON, but for now, you can do this:
import {promises as fs} from 'fs';
const packageJson = JSON.parse(await fs.readFile('package.json', 'utf8')).