Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ERR_ESM_REQUIRE - Webpack 5 config should support ESM packages #23725

Closed
mikestopcontinues opened this issue Apr 6, 2021 · 44 comments
Closed
Assignees
Milestone

Comments

@mikestopcontinues
Copy link

What version of Next.js are you using?

10.1.3

What version of Node.js are you using?

14.x

What browser are you using?

Chrome

What operating system are you using?

macOS

How are you deploying your application?

Vercel

Describe the Bug

p-queue recently updated to using ESM modules, and it looks like some webpack configuration is required to support it. I doubt this is the last time this particular issue will come up.

Expected Behavior

Users should be able to require ESM modules without getting an error.

To Reproduce

Install [email protected], import it, and try to start next.

Thanks!

@mikestopcontinues mikestopcontinues added the bug Issue was opened via the bug report template. label Apr 6, 2021
@timneutkens timneutkens added please add a complete reproduction The issue lacks information for further investigation and removed bug Issue was opened via the bug report template. labels Apr 6, 2021
@stefanprobst
Copy link
Contributor

not the op, but reproducible with this. both import and import() fail with:

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /data/Development/playground/issue-next-esm/node_modules/p-queue/dist/index.js
require() of ES modules is not supported.
require() of /data/Development/playground/issue-next-esm/node_modules/p-queue/dist/index.js from /data/Development/playground/issue-next-esm/.next/server/pages/index.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename /data/Development/playground/issue-next-esm/node_modules/p-queue/dist/index.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /data/Development/playground/issue-next-esm/node_modules/p-queue/package.json.

@mikestopcontinues
Copy link
Author

Thanks @stefanprobst I didn't see they'd requested a repro. :)

@maiertech
Copy link

maiertech commented May 1, 2021

Some background: @sindresorhus is in the process of moving most of his packages to ESM only in 2021. This error will likely become more common as more packages move to ESM only.

I ran into the same issue with https://github.com/sindresorhus/slugify. Workaround: don't upgrade to latest major.

@yurtaev
Copy link

yurtaev commented May 1, 2021

workaround: use next-transpile-modules

const withTM = require('next-transpile-modules')([
 // ...
  'p-debounce', // ESM module
])

@mikestopcontinues
Copy link
Author

I like @yurtaev's solution, but if anyone's relying on npm-check-updates, my fix was to prefix breaking module versions with =, then run ncu -u --rejectVersion '/^=/'.

@nemanja-tosic
Copy link

nemanja-tosic commented May 13, 2021

We have encountered the same issue with yjs (version 13.5.5). For us, webpack was compiling the module version of yjs, but was not compiling anything yjs was importing, namely a package called lib0. This resulted in an ESM (yjs) importing a CJS module (lib0). Low level, in case it helps anyone: the specific issue was that yjs was adding suffixes to all imports (eg import { observable } from 'lib0/observable.js) which was invalidating conditional exports, resulting to the ESM => CJS import mentioned above.

The solution for us was to add the following line to next.config.js:

module.exports = {
  webpack: function (config, options) {
    config.externals = [...config.externals, 'yjs'];

    return config;
  },
};

This makes webpack treat yjs as an external dependency (non-transpiled that is), and everything goes through the proper builds.

UPDATE: no, this only made the build work. I saw a require('yjs'); in the server build artifacts, but it does not work on the client.

@mario-jerkovic
Copy link

Same issue with new version of d3 modules like d3-scale

@advaiyalad
Copy link

A more permanent solution would be to import() everything instead of require()ing it. This is possible since next no longer supports node 10 in canary.

next.js/package.json

Lines 140 to 142 in f18ce55

"engines": {
"node": ">=12.0.0"
}

@JohnForster
Copy link

JohnForster commented Jun 17, 2021

This still has the "please add a complete reproduction" tag, so I'm linking a minimal repo:

https://github.com/JohnForster/esm-minimal-repo

This example also does not work with withTM, so if anyone can give advice on how to get it running, I'd appreciate it.

@JohnForster
Copy link

JohnForster commented Jun 17, 2021

For anyone running into similar problems ( @mario-jerkovic ?) that aren't immediately fixed with next-transpile-modules, you may need to include sub-dependencies in your next.config.js as well. I just ran into this problem with d3-delaunay but it might be present in other d3 modules as well.

Keep an eye on the error messages to see which modules you need to add.

My config looks like:

// next.config.js
const withTM = require("next-transpile-modules")([
  "d3-delaunay", // The package I'm trying to import
  "delaunator", // A dependency of d3-delaunay
  "robust-predicates", // A dependency of delaunator
]);

module.exports = withTM({
  reactStrictMode: true,
});

@advaiyalad
Copy link

Could the tag please add a complete reproduction please be removed, as this issue has a reproduction?

@timneutkens timneutkens added kind: story and removed please add a complete reproduction The issue lacks information for further investigation labels Jul 12, 2021
@timneutkens
Copy link
Member

This is being worked on by @sokra currently, you can check out the initial PR here: #27069. Do keep in mind this is still work in progress.

@sokra
Copy link
Member

sokra commented Jul 12, 2021

You can try the latest canary version and verify if it does work in your cases.

@talentlessguy
Copy link

talentlessguy commented Jul 14, 2021

@sokra I don't know if this is a bug or not, but when a pure ESM library imports a library that has "module" (non-standard ESM field) and "main" but not "exports", it fails. Is it planned to support non-standard fields? Or "exports" only? There is a large set of such libraries with "main" / "module" fields, so that's why I'm asking

@sokra
Copy link
Member

sokra commented Jul 14, 2021

Do you have a name of such a package for reference?

@stefanprobst
Copy link
Contributor

it has been working for me with xdm and retext 🤷

@timneutkens
Copy link
Member

@frattaro can you make sure you're on next@canary?

@frattaro
Copy link

frattaro commented Aug 4, 2021

Definitely am

@timneutkens
Copy link
Member

Can you provide a reproduction? Then we can have a look into it 👍

@frattaro
Copy link

frattaro commented Aug 5, 2021

Creating the repro revealed my issue. Alone, using esmExternals with the unified stack works just fine.

I have another package that uses imports, does not have type: "module" in it's package.json and needs next-transpile-modules. Unfortunately, it seems you can't use esmExternals alongside next-transpile-modules. So I added type: "module" directly to the package.json of the package in question, and then found another issue with it. It has a babel preset that uses require in it. I renamed the babel preset's suffix to .cjs, and that worked. But then I ran into:

error - ./node_modules/@my-package/path/app.scss
Global CSS cannot be imported from within node_modules.

And at that point I stopped trying to fix it :)

Edit: the package I'm importing is a UI framework, so it's going to have some edge cases

@exneval
Copy link

exneval commented Aug 7, 2021

another version of @frattaro

I'm using rehype-raw, rehype-slug, remark-gfm

const withTM = require("next-transpile-modules")([
  "bail",
  "ccount",
  "comma-separated-tokens",
  "hast-to-hyperscript",
  "hast-util-from-parse5",
  "hast-util-has-property",
  "hast-util-heading-rank",
  "hast-util-parse-selector",
  "hast-util-raw",
  "hast-util-to-parse5",
  "hast-util-to-string",
  "hastscript",
  "html-void-elements",
  "is-plain-obj",
  "markdown-table",
  "mdast-util-find-and-replace",
  "mdast-util-from-markdown",
  "mdast-util-gfm",
  "mdast-util-to-markdown",
  "micromark-extension-gfm",
  "micromark-factory-space",
  "micromark-util-combine-extensions",
  "micromark-util-character",
  "micromark-util-chunked",
  "micromark-util-classify-character",
  "micromark-util-encode",
  "micromark-util-resolve-all",
  "micromark-util-sanitize-uri",
  "micromark-util-symbol",
  "property-information",
  "rehype-raw",
  "rehype-slug",
  "remark-gfm",
  "remark-parse",
  "space-separated-tokens",
  "trough",
  "unified",
  "unist-util-stringify-position",
  "vfile-location",
  "web-namespaces",
]);

@deadcoder0904
Copy link

deadcoder0904 commented Aug 12, 2021

@exneval I'm trying to use it with unist-util-visit & I used next-transpile-modules like you said but still getting an error:

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: my-app\node_modules\unist-util-visit\index.js
require() of ES modules is not supported.
require() of my-app\node_modules\unist-util-visit\index.js from my-app\rehype\highlight-code.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename index.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from my-app\node_modules\unist-util-visit\package.json.

    at new NodeError (node:internal/errors:363:5)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1126:13)
    at Module.load (node:internal/modules/cjs/loader:989:32)
    at Function.Module._load (node:internal/modules/cjs/loader:829:14)
    at Module.require (node:internal/modules/cjs/loader:1013:19)
    at require (node:internal/modules/cjs/helpers:93:18)
    at Object.<anonymous> (my-app\rehype\highlight-code.js:4:15)
    at Module._compile (node:internal/modules/cjs/loader:1109:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1138:10)
    at Module.load (node:internal/modules/cjs/loader:989:32) {
  code: 'ERR_REQUIRE_ESM'

next.config.js

const withTranspileModules = require('next-transpile-modules')([
	'hast-util-to-html',
	'hast-util-to-string',
	'rehype-slug',
	'remark-gfm',
	'remark-parse',
	'unified',
	'unist-util-visit',
])

const withBundleAnalyzer = bundleAnalyzer({
	enabled: process.env.ANALYZE === 'true',
})

module.exports = withTranspileModules(withBundleAnalyzer(nextConfig))

I even tried changing my custom ./rehype/highlight-code.js to use import instead of require but it gave:

SyntaxError: Cannot use import statement outside a module

Do I need to do anything else?

@exneval
Copy link

exneval commented Aug 12, 2021

@deadcoder0904 maybe setup issue? I'm using next compose plugins to wrap the transpile,

This config, for latest rehype-raw, rehype-slug and remark-gfm v1.0.0

const withPlugins = require("next-compose-plugins");
const withTM = require("next-transpile-modules")([
  "escape-string-regexp",
  "comma-separated-tokens",
  "hast-to-hyperscript",
  "hast-util-from-parse5",
  "hast-util-has-property",
  "hast-util-heading-rank",
  "hast-util-parse-selector",
  "hast-util-raw",
  "hast-util-to-parse5",
  "hast-util-to-string",
  "hastscript",
  "html-void-elements",
  "property-information",
  "rehype-raw",
  "rehype-slug",
  "space-separated-tokens",
  "vfile-location",
  "web-namespaces",
]);

const nextConfig = {
  eslint: {
    ignoreDuringBuilds: true,
  },
};

module.exports = withPlugins([withTM], nextConfig);

or maybe you can try NextJS 11.1.0 , and try

// next.config.js
module.exports = {
  // Prefer loading of ES Modules over CommonJS
  experimental: { esmExternals: true }
}

no need to use transpile anymore, finally NextJS support it, and it become default in NextJS 12

@deadcoder0904
Copy link

@exneval I thought I needed to use even next-transpile-modules to make ESM modules work with Next.js v11.1.0. If it's not the case, then I'm wondering why it isn't working?

You also don't need to use next-compose-plugins as it would work properly even without it if you wrap it. I'll probably open an issue on unist-util-visit.

@timneutkens
Copy link
Member

@deadcoder0904 can you provide a reproduction repository so that we can have a look?

@deadcoder0904
Copy link

@timneutkens take a look here -> https://github.com/deadcoder0904/next-esm-error

Install & run to see errors :)

@stefanprobst
Copy link
Contributor

@deadcoder0904
looks like you didn't actually enable the esmExternals config?

@deadcoder0904
Copy link

@stefanprobst I did actually, just not in the repro. Pushed a new commit but still error :)

@sokra
Copy link
Member

sokra commented Aug 12, 2021

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /../next-esm-error/node_modules/hast-util-to-string/index.js
require() of ES modules is not supported.
require() of /../next-esm-error/node_modules/hast-util-to-string/index.js from /../next-esm-error/rehype/highlight-code.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename index.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /../next-esm-error/node_modules/hast-util-to-string/package.json.

@deadcoder0904 Your problem is unrelated to next.js/webpack processing your files.

You are trying to require() an ESM, which is not allowed (which is also want the node.js error is trying to tell you). You need to use import or import() to import an ESM.

This happens while loading the next.config.js.

Sadly next.js require()s the config file, so you can't really use import there. I guess that need to be changed in next.js

@deadcoder0904
Copy link

deadcoder0904 commented Aug 13, 2021

@sokra but I can't import ESM modules from the folder rehype/ as it gives another error:

SyntaxError: Cannot use import statement outside a module

I already said this above :)

Sadly next.js require()s the config file, so you can't really use import there. I guess that need to be changed in next.js

Got it. So I cannot use ESM till next.config.js can use import()? Till then, is there any issue I should subscribe to?

Edit: 13 hours later, came back to the same issue & looks like this is the issue I should be subscribed to :)

@Prakhar-FF13
Copy link

Prakhar-FF13 commented Aug 31, 2021

Failed to require remark-math.

I have to import remark-math in next.config.js . It gives this error when trying to import. I am on next@canary.

Error: failed to load next.config.js, see more info here https://nextjs.org/docs/messages/next-config-error
Error [ERR_REQUIRE_ESM]: require() of ES Module /Users/abc/Desktop/portfolio/node_modules/remark-math/index.js from /Users/abc/Desktop/portfolio/next.config.js not supported.
Instead change the require of index.js in /Users/abc/Desktop/portfolio/next.config.js to a dynamic import() which is available in all CommonJS modules.
at Object. (/Users/abc/Desktop/portfolio/next.config.js:1:20)
at Object.loadConfig [as default] (/Users/abc/Desktop/portfolio/node_modules/next/dist/server/config.js:347:32)
at async NextServer.loadConfig (/Users/abc/Desktop/portfolio/node_modules/next/dist/server/next.js:112:22)
at async NextServer.prepare (/Users/abc/Desktop/portfolio/node_modules/next/dist/server/next.js:94:24)
at async /Users/abc/Desktop/portfolio/node_modules/next/dist/cli/next-dev.js:121:9 {
code: 'ERR_REQUIRE_ESM'
}

@lunelson
Copy link

lunelson commented Sep 2, 2021

I'm guessing the use-case for importing remark and rehype plugins in next.config.js is about configuring a markdown or MDX loader for webpack?

The whole unifiedjs ecosystem has moved to ESM but all those plugins also have previous versions that were commonjs format, you can probably make this work if you roll them back to their previous major releases

@Prakhar-FF13
Copy link

Yes, that is what I am thinking of doing.

@christopher-caldwell
Copy link

experimental: {
    esmExternals: true,
  },

This worked perfectly for me. Using "next": "11.1.3-canary.7" and "unified": "10.1.0"

@timneutkens
Copy link
Member

timneutkens commented Oct 15, 2021

esmExternals: true is now the default on next@canary meaning it is going to be the default in the upcoming stable release. I'm going to close this issue as this particular case has been fixed. For loading ESModules in next.config.js please subscribe to #9607.

@ijjk ijjk closed this as completed Oct 16, 2021
@eric-burel
Copy link
Contributor

@Prakhar-FF13 by any chance, did you manage to setup math display in MDX?

@Prakhar-FF13
Copy link

No I used mdx bundler by Kent c Dodds.

@balazsorban44
Copy link
Member

This issue has been automatically locked due to no recent activity. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@vercel vercel locked as resolved and limited conversation to collaborators Feb 12, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests