opened
natemoo-re
username_0
# Feature request

## Is your feature request related to a problem? Please describe.

A clear and concise description of what you want and what your use case is.

## Describe the solution you'd like

A clear and concise description of what you want to happen.

## Describe alternatives you've considered

A clear and concise description of any alternative solutions or features you've considered.

## Additional context

Add any other context or screenshots about the feature request here.
Support esm next.config.js
issue
closed
natemoo-re
username_0
issue
reopened
natemoo-re
username_0
# Feature Request

## Is your feature request related to a problem? Please describe.

With Node v13.2.0 landing [native support for ES modules](https://nodejs.org/api/esm.html), I would expect `next.config.js` to support ES module format in addition to CJS.

When using `type: module` in `package.json` on Node v13.2.0 and an ESM `next.config.js` format, Next throws an error due to the config resolution logic relying on `require`.

## Describe the solution you'd like

Next should follow Node’s module semantics and allow either CJS or ESM file, depending on user configuration.

Currently, `next.config.js` uses CJS with `require` and `module.exports`. ESM format would allow users to `import` dependencies and `export default` the config object.

## Describe alternatives you've considered

This theoretically also opens the door to mirror Node’s explicit file extension pattern, which would suggest support for `next.config.cjs` and `next.config.mjs` files. This is likely controversial, but it is part of the language.
Support esm next.config.js
issue
created
redblue9771
username_1
Node 13 is not yet suitable for production environments, and using the mjs extension is intrusive.  Recently I needed a custom server to use better express middleware features, but I have no way to use ESM in any custom server related files.  I hope to add an example about using EMS and nodemon when customizing the server
comment
created
natemoo-re
username_0
While I’d love to see ESM support globally in Next, this issue is just about the `next.config.js` file. Custom servers can support ESM in a similar manner to the [custom-server-typescript](https://github.com/zeit/next.js/tree/canary/examples/custom-server-typescript) example.

Let’s not get into a discussion about the merits of `.mjs` or `.cjs`. I’m personally not a big fan, but since Node allows both, Next should support them as well.
comment
created
afsanefda
username_2
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /.../next.config.js
require() of ES modules is not supported.
require() of /..../node_modules/next/dist/next-server/server/config.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 next.config.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /.../package.json.
```
comment
created
baocang
username_3
native support for ES modules +1
comment
created
cooervo
username_4
same here tried to migrate project to use import just to fail on next.config.js
comment
created
OctonianCat
username_5
Would love to see this implemented. +1
comment
created
hypo-thesis
username_6
This is a bummer. no solution yet ?
comment
created
Willi-Smith
username_7
Any progress in implementation of esm syntax so far?
comment
created
crshumate
username_8
For anyone running up against this issue. I am using a custom server for complete flexibility in my build.  

Node files are located in a top level dir called `server` and Next files are in a top level dir called `src`

```
- next.config.js
- package.json - make no changes to this file

- /src
    - /pages

- /server
    - package.json
        - this file just needs: {"type":"module"}
    - server.js
```

As noted in the structure above, place an empty `package.json` file in a subdir with the node/express/etc files.
In this `package.json` simply add `{"type":"module"}`
Ensure all the `requires` are changed to ES6 `import` statements and it should build fine.
comment
created
sagirk
username_9
Nice! 👍

If you want to retain `server.js` in the root, though, simply rename it from `server.js` to `server.mjs`. Works without requiring a `type` entry in `package.json`.
comment
created
Rowno
username_10
Since Node.js 12.17.0 ES modules have been enabled by default (a flag is no longer required). So ES modules are now available in an LTS version of Node.js:
https://nodejs.org/en/blog/release/v12.17.0/

Also it looks like you can use normal `.js` file extensions if you add `"type": "module"` to your `package.json`:
https://nodejs.org/docs/latest-v12.x/api/esm.html#esm_package_json_type_field
comment
created
andreasg123
username_11
Is the use of [next-transpile-modules](https://www.npmjs.com/package/next-transpile-modules) still the only way to include modules that only provide ESM?  I tried switching my project to `"type": "module"` but I was prompted to rename `next.config.js` to `.cjs`.  The latter wasn't picked up as a config file, resurfacing an issue with `"fs"` in another module.

In case it is relevant, my project uses TypeScript.  I had to include `babel-jest` to be able to use Jest.

My final goal is to use `next export` because the production server doesn't run Node.
comment
created
paulshorey
username_12
I ran into a similar issue. If any of the folders inside my Next.js project use {type:"module"}, then `next build` process can't require() from them. It says "Must use import to load ES Module". 

The silly thing is that Webpack/React uses ES Module format (import instead of require). So this is very strange. Next.js server really should use ESM by default, because it's working with an ESM filesystem.
comment
created
GitHubFilipe
username_13
Im running into this issue too.
A .js script that I'm importing in my next.config.js, uses "import {...} from '...' directives to call some API functions, thus throwing the error: 
_SyntaxError: Cannot use import statement outside a module_

no matter how I turn it, the combination just doesn't work.
comment
created
belgattitude
username_14
For information, ky will move to esm only... next-transpile-modules can be used meanwhile, but esm would be really appreciated.

https://github.com/sindresorhus/ky/issues/322#issuecomment-773850479
comment
created
Janpot
username_15
Created an RFC (https://github.com/vercel/next.js/discussions/22381) and prototype (https://github.com/vercel/next.js/pull/22153) for this
comment
created
JerryGreen
username_16
ESM is cool, but what about typescript? Will that be `.mts`? 😅
comment
created
natemoo-re
username_0
In all seriousness, TypeScript probably isn't that big of a leap from here. Async config loading was the biggest problem but is addressed in #22153. Node is currently stabilizing the experimental [`loaders`](https://nodejs.org/api/esm.html#esm_loaders) API, which will expose hooks to transform non-standard file formats like TypeScript.
comment
created
Joe-Connolly
username_17
this solution (inspired by another github issue https://github.com/vercel/next.js/issues/5318#issuecomment-575959060) worked for me for importing a typescript file that contained ES6 imports/exports:
```
const BASE_CSP = requireTypescript("./getContentSecurityPolicy.ts");
const withImages = require("next-images");

module.exports = withImages({
    async headers() {
        return [
            {
                source: "/:path*{/}?",
                headers: [
                    {
                        key: "Content-Security-Policy",
                        value: BASE_CSP,
                    },
                ],
            },
        ];
    },
});

// only CommonJS files can be imported in next.config, so need to transform imports
function requireTypescript(path) {
    const fileContent = require("fs").readFileSync(path, "utf8");
    const compiled = require("@babel/core").transform(
        fileContent,
        {
            filename: path,
            presets: [ "@babel/preset-typescript" ],
            plugins: [ "@babel/plugin-transform-modules-commonjs" ],
        },
    );

    // eslint-disable-next-line no-eval
    return eval(compiled.code);
}
```
comment
created
meglio
username_18
Dear community, while using `next-transpile-module` helps with 3rd party libraries, I could not use it for the .mjs files that I authored as part of the project. How do I do it? Please advise.
comment
created
christopherjbaker
username_19
I am very confused. Things may have been different when this ticket was opened, but now Webpack supports this out of the box and Nodejs supports this out of the box. I'm confused why Next.js is built in such a way that this standards-compliant behaviour does not work in Next.js. Using `next-transpile-modules` is a workaround and does not count as "works".
comment
created
deadcoder0904
username_20
Any updates on this?

Here's a good guide on how to make pure ESM package → https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
comment
created
izaleu
username_21
I'm trying to pull some logic out of the SSR portion of my app into the server side of things as part of a refactor. Unfortunately I'm going to have to maintain a separate, CJS copy of what should be shared code, because the originals are written in ESM and I can't seem to get next/webpack/node to all be happy at once. (Don't get me started on optional chaining.)

Please add support for this. 

I am using Webpack 5, Node 14 and Next 10.0.5.
comment
created
IdkMan2Usertive
username_22
I am also looking for a way to use ESM system here. 
I have followed Material-UI guide to minimize bundle size and improve development server performance (https://material-ui.com/guides/minimizing-bundle-size/) and I am stuck on the same error.
comment
created
rnarkk
username_23
I put some questions on @username_15's RCF https://github.com/vercel/next.js/discussions/22381#discussioncomment-881384 to catch up with the status of the issue. Can someone help me understand the intricacy of the problem and draw the roadmap by answering my questions or giving me some general directions to solve the problem?

If the problem is entailing essential or not-straightforward-to-solve trade-offs between CommonJS and ESM or Webpack 4 and Webpack 5, do the core team have a *transition strategy*? How far the investigation has been proceeding? If you could share the internal status or consensus, it would be so much helpful.

Also looking for a further review and comments @username_15's PR https://github.com/vercel/next.js/pull/22153. (The current conflict is a one-line tweak to resolve.)

Thanks,
comment
created
entrptaher
username_24
Here is my current workaround with esm or jiti, and yarn.

First install yarn, and esm or jiti.

```
yarn add esm
```

Then, create a .yarnrc file at root of the nextjs project where you have package.json

```sh
yarn-path "./.yarn.js"
```

Now try either of these,

```sh
NODE_OPTIONS="--require esm" yarn next build
```

Or,

Create a .yarn.js file which will be used to load esm right before 

```js
"use strict"

const child_process = require("child_process")
const { env } = process
const { parent } = module

const REQUIRE_ESM = "--require esm"
const REQUIRE_DOT_YARN = "--require ./.yarn.js"

let { NODE_OPTIONS } = env

if (typeof NODE_OPTIONS === "string") {
  NODE_OPTIONS += " "
} else {
  NODE_OPTIONS = ""
}

if (parent != null &&
    parent.id === "internal/preload") {
  env.NODE_OPTIONS = NODE_OPTIONS.replace(REQUIRE_DOT_YARN, REQUIRE_ESM)
} else {
  child_process.spawn("yarn", process.argv.slice(2), {
    env: Object.assign({}, env, {
      NODE_OPTIONS: REQUIRE_DOT_YARN + " " + NODE_OPTIONS
    }),
    stdio: "inherit"
  })
}
```

Now whenever you do next using yarn, it will process that next.config.js file through esm,

```sh
yarn next build
```
comment
created
stringa
username_25
@Edheltur Can this be done with npm?
comment
created
bartlangelaan
username_26
I think support for this is being worked on.

I found the following PR: https://github.com/vercel/next.js/pull/27069
It is released in v11.0.2-canary.10 and newer.

Since I have updated to the canary version, I don't get this error anymore.
comment
created
Himself65
username_27
seems like next.js doesn't support [unist-util-visit](https://www.npmjs.com/package/unist-util-visit) `v4.x`
comment
created
delbaoliveira
username_28
Hey @username_27, I recently came across this issue with `unist-util-visit` for something I'm working on related to MDX. The import changed from `import visit from 'unist-util-visit'` to `import { visit } from 'unist-util-visit'` in v3.0. Hopefully, that's helpful!
comment
created
Beraliv
username_29
I replaced and it didn't help 😓

I will share logs

But all in all, it was here before the rebase - https://github.com/username_29/beraliv.dev/pull/215 (it removed my change with { visit })
comment
created
stefanprobst
username_30
you cannot currently import ESM-only packages (like `unist-util-visit@4`) in `next.config.js` (see [this comment](https://github.com/vercel/next.js/issues/23725#issuecomment-897730810)). it should work fine anywhere else when setting the experimental `esmExternals` option.
comment
created
stringa
username_25
I was able to get esm modules working after updating to at least Next@11.0.2
comment
created
equinusocio
username_31
Same issue here with nextjs `11.1.0` and rehype plugins for `@next/mdx`. I have to replace the deprecated `remark-autolink-headings` with the new `rehype-autolink-headings` which has `type: module` inside the package and doesn't work, Same for the new `rehype-slug` version.
comment
created
stringa
username_25
I had these issues until I moved over to next 11.0.2 canary
comment
created
equinusocio
username_31
@username_25 are you suggesting that downgrading to 11.0.2 solves the issue?
comment
created
jamesTbaker
username_32
If I'm correctly understanding the [11.1.0 release notes](https://github.com/vercel/next.js/releases/tag/v11.1.0), this issue was resolved in 11.1.0.
comment
created
Himself65
username_27
I replace it with `import('xxx')`, and seems to works.

```diff
Index: lib/img-to-jsx.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/lib/img-to-jsx.js b/lib/img-to-jsx.js
--- a/lib/img-to-jsx.js	(revision 0ec5b1d2dfbe0c6852d0eaee92b741583a9b89ad)
+++ b/lib/img-to-jsx.js	(revision 39eddb60b3c978a708b609ab305f007a7540d8e1)
@@ -1,8 +1,8 @@
-const visit = require('unist-util-visit')
 const sizeOf = require('image-size')
 const fs = require('fs')
 
-module.exports = (options) => (tree) => {
+module.exports = (options) => async (tree) => {
+  const { visit } = await import('unist-util-visit')
   visit(
     tree,
     // only visit p tags that contain an img element
Index: lib/mdx.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/lib/mdx.js b/lib/mdx.js
--- a/lib/mdx.js	(revision 0ec5b1d2dfbe0c6852d0eaee92b741583a9b89ad)
+++ b/lib/mdx.js	(revision 39eddb60b3c978a708b609ab305f007a7540d8e1)
@@ -4,7 +4,6 @@
 import { serialize } from 'next-mdx-remote/serialize'
 import path from 'path'
 import readingTime from 'reading-time'
-import visit from 'unist-util-visit'
 import imgToJsx from './img-to-jsx'
 import getAllFilesRecursively from './utils/files'
 
@@ -49,6 +48,7 @@
     : fs.readFileSync(mdPath, 'utf8')
 
   const { data, content } = matter(source)
+  const { visit } = await import('unist-util-visit')
   const mdxSource = await serialize(content, {
     components: MDXComponents,
     mdxOptions: {
```
comment
created
stefanprobst
username_30
i would add that it's perfectly ok to just keep using the previous major version of `unified` packages (`unist-util-visit@3` in this case, which works with `unified@9` / `remark@13`), until esm support has improved throughout the ecosystem.
comment
created
TamDc
username_33
Any solution for this guy? I have the same problem when optimizing my nextjs project.
comment
created
stfenjobs
username_34
same here:

nextjs: 11.1.0

I want use a remark plugins , some code like this :
```

import {visit} from 'unist-util-visit'
...


```
comment
created
nedkelly
username_35
I'm having the same issue with `react-markdown`.

TypeScript
Next.js 11.1.0
Yarn 2

I tried adding `esmExternals` in `next.config.js` but still no joy.

Using Dynamic import fixes it though:

```javascript
const ReactMarkdown = dynamic(() => import('react-markdown'));
```
comment
created
equinusocio
username_31
Are you doing this inside next config?
comment
created
city17
username_36
Same problem here, unable to get remark-slug or rehype-slug working due to this error.
comment
created
stringa
username_25
Just use

const a = import('react-markdown') where ever you want to use the dependency
comment
created
equinusocio
username_31
You can't use import insite next config..
comment
created
nedkelly
username_35
No, and to be honest, using dynamic import is a little unstable, it sometimes fails to load so it's not really a fix. And it doesn't work in next.config.js.
comment
created
alecmev
username_37
No disrespect to the participants, but I think too many people misunderstand this issue, resulting in all sorts of irrelevant ESM problems being reported here. Can commenting be limited to collaborators, please?
comment
created
equinusocio
username_31
So we are all stupid. Ok. Anyway the issue is pretty clear, any nextjs plugin which are now modules are totally unusable because nextjs config file doesn't support modules.
comment
created
Richienb
username_38
![No, No. He's Got a Point](https://user-images.githubusercontent.com/29491356/134623442-749b7e10-4472-4b50-a935-426d76ba9612.png)

This issue was for allowing the `next.config.js` to be written with ESM. The most recent conversation is for allowing ESM modules to be loaded within the source code.

The best thing to do is to move this part of the conversation to a seperate issue and guide people who want to talk about that specific thing there.

To people who are having trouble loading modules written in ESM: create a reproduction repository and create a new bug report. As for general discussion about it, we have Discussions.
comment
created
equinusocio
username_31
That's totally different from saying "let's close the comments". Anyway, this is the issue i want to follow.
comment
created
ctjlewis
username_39
comment
created
rnarkk
username_23
@username_39 Thank you for sharing your exploration. Based on it, do you think anything else will be straightforward in rewriting CJS to ESM when Jest's ESM support is solved?

---

 * https://github.com/facebook/jest/issues/9430 to follow the progress of Jest's ESM support.
comment
created
ctjlewis
username_39
@username_23 There are a few obstacles (some related to [TS itself](https://github.com/microsoft/TypeScript/issues/42151), which we may be able to workaround with [Node12 resolution](https://github.com/microsoft/TypeScript/pull/44501) as of next release) to getting Next to that point, which I will detail in a separate issue and link here, but the way I'd propose implementing it, you would just need to set `"type": "module"` or use `.mjs` extension to signal ESM, and Next would handle the rest after you rewrite it.

For TS projects, you'd want to configure your local project settings to use the new Node12 resolution, so that it forces you to write complete ESM-compatible import specifiers (or use something like [tszip](https://github.com/tszip/tszip) to rewrite them for you, which is what I do).
comment
created
timneutkens
username_40
I've opened a PR that changes from `require()` to `import()` for config loading and adds support for `next.config.mjs`. I'll keep this issue open as there's still more work to do for `"type": "module"` in `package.json` but this change should help until then: https://github.com/vercel/next.js/pull/29935
comment