Skip to content

Support ES module format (ESM) in next.config.js #9607

Closed
@natemoo-re

Description

@natemoo-re

Feature request

With Node 12.17.x landing native support for ES modules, 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.1.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.

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.

Describe alternatives you've considered

As statically analyzing the native module format of next.config.js likely introduces a fair amount of complexity, this could be used as an opportunity to introduce "superset" config files (ESM, TypeScript [see #5318, #8044]) which are transpiled to CJS, emitted to the distDir (.next), and read from that location. This would also allow users pinned versions of Node below 13 to benefit from ESM format or strongly typed config files (see @stencil/core for prior art.)

Additional context

The following error is thrown, minimum reproducible files below.

node:97960) Warning: require() of ES modules is not supported.
require() of /PROJECT_NAME/next.config.js from /PROJECT_NAME/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 /PROJECT_NAME/package.json.
/PROJECT_NAME/next.config.js:1
import path from "path";
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at wrapSafe (internal/modules/cjs/loader.js:983:16)
    at Module._compile (internal/modules/cjs/loader.js:1033:27)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1103:10)
    at Module.load (internal/modules/cjs/loader.js:914:32)
    at Function.Module._load (internal/modules/cjs/loader.js:822:14)
    at Module.require (internal/modules/cjs/loader.js:956:19)
    at require (internal/modules/cjs/helpers.js:74:18)
    at Object.loadConfig [as default] (/PROJECT_NAME/node_modules/next/dist/next-server/server/config.js:105:34)
    at new Server (/PROJECT_NAME/node_modules/next/dist/next-server/server/next-server.js:42:43)
    at new DevServer (/PROJECT_NAME/node_modules/next/dist/server/next-dev-server.js:1:2508)

package.json

{
  "type": "module"
  ...
}

next.config.js

// next.config.js
import withCSS from '@zeit/next-css';
export default withCSS();

Metadata

Metadata

Assignees

No one assigned

    Labels

    WebpackRelated to Webpack with Next.js.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions