Skip to content

Issue with backend-side ES6 imports with "type":"module" with an express/nextjs setup #24334

@alexey-dc

Description

@alexey-dc

What version of Next.js are you using?

10.1.3

What version of Node.js are you using?

15.9.0

What browser are you using?

Chrome

What operating system are you using?

MacOS

How are you deploying your application?

Running locally via express

Describe the Bug

I have an Express.js server that sets up Next.js, and I want to use ES6 modules with my backend.

My package.json has the line "type": "module", which enables ES6 module support in Node.js. Everything is imported fine, but when I try to load a page, I get the following exception:

error - Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /Users/alexey/work/alexey/temp/.next/server/pages/_document.js
require() of ES modules is not supported.
require() of /Users/alexey/work/alexey/temp/.next/server/pages/_document.js from /Users/alexey/work/alexey/temp/node_modules/next/dist/next-server/server/require.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 _document.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /Users/alexey/work/alexey/temp/package.json.

    at new NodeError (node:internal/errors:329:5)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1108:13)
    at Module.load (node:internal/modules/cjs/loader:971:32)
    at Function.Module._load (node:internal/modules/cjs/loader:812:14)
    at Module.require (node:internal/modules/cjs/loader:995:19)
    at require (node:internal/modules/cjs/helpers:92:18)
    at requirePage (/Users/alexey/work/alexey/temp/node_modules/next/dist/next-server/server/require.js:1:1184)
    at loadComponents (/Users/alexey/work/alexey/temp/node_modules/next/dist/next-server/server/load-components.js:1:795)
    at DevServer.findPageComponents (/Users/alexey/work/alexey/temp/node_modules/next/dist/next-server/server/next-server.js:77:296)
    at DevServer.renderErrorToHTML (/Users/alexey/work/alexey/temp/node_modules/next/dist/next-server/server/next-server.js:139:29)
    at DevServer.renderErrorToHTML (/Users/alexey/work/alexey/temp/node_modules/next/dist/server/next-dev-server.js:35:1392)
    at runMicrotasks (<anonymous>)
    at processTicksAndRejections (node:internal/process/task_queues:94:5)
    at async DevServer.renderError (/Users/alexey/work/alexey/temp/node_modules/next/dist/next-server/server/next-server.js:138:1659) {
  code: 'ERR_REQUIRE_ESM'
}

Indeed, looking at .next/server/pages/_document.js, it has a var installedModules = require('../ssr-module-cache.js'); directive, which is against the rules for "type": "module".

This seems to imply that I can not use Next.js with ES6 syntax in Node - which is too bad!

Expected Behavior

I think what I would expect is that Next.js would compile in a way that's compatible with ES6 modules - i.e. when "type": "module" is enabled, it relies on import, not require

To Reproduce

I've created a minimal setup where I'm able to get this to reproduce:

package.json

{
  "scripts": {
    "start": "node index.js"
  },
  "name": "es6_import_issue",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "author": "Alexey Chernikov",
  "dependencies": {
    "express": "^4.17.1",
    "next": "^10.1.3",
    "react": "^17.0.2",
    "react-dom": "^17.0.2"
  },
  "type": "module"
}

index.js

/*
  This style works if I don't do "type": "module"
  in package.json - main.jsx loads fine!
*/
/*
const express = require('express');
const next = require('next');
const http = require('http');
*/
/*
  With this style and "type": "module" in package.json
  I get the error described
*/
import express from 'express';
import next from 'next';
import http from 'http';

class Server {
  constructor(port) {
    this.port = port;
    this.express = express();
    this.next = next({ dev: process.env.NODE_ENV !== 'production' });
  }

  async start() {
    await this.next.prepare();
    this.express.get('/', (req, res) => {
      return this.next.render(req, res, `/main`, req.query);
    })

    this.express.get('*', (req, res) => {
      return this.next.render(req, res, `/${req.path}`, req.query);
    })

    this.server = http.createServer(this.express);
    this.server.listen(this.port);
  }
}

const begin = async () => {
  const port = 3000;
  new Server(port).start();
  console.log(`Server running on port ${port}`);
};

begin();

And also in pages/main.jsx:

const hello = () => {
  return <div>
    Hello world
  </div>
}

export default hello

With this setup, after a yarn install and yarn start, I see the error above. I left the require style that works fine w/o a "type": "module" directive in comments so it's quick to test that this Express+Next.js setup is in fact functional.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugIssue was opened via the bug report template.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions