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

Missing webpack dependency when using output standalone + custom server #64031

Open
maximelebastard opened this issue Apr 3, 2024 · 14 comments · Fixed by #72966
Open

Missing webpack dependency when using output standalone + custom server #64031

maximelebastard opened this issue Apr 3, 2024 · 14 comments · Fixed by #72966
Labels
bug Issue was opened via the bug report template. Output (export/standalone) Related to the the output option in `next.config.js`.

Comments

@maximelebastard
Copy link

maximelebastard commented Apr 3, 2024

Link to the code that reproduces this issue

https://github.com/maximelebastard/nextjs-issue-custom-server

To Reproduce

The issue is related to using the output: "standalone" with a custom server. See example repository.

  1. Clone the reproducing repository
  2. Run npm install then npm run build and npm run start
  3. When starting the app, an error will be triggered due to a missing webpack file on a webpack require (see the error below)
  4. To see the code triggering this issue, see this commit: maximelebastard/nextjs-issue-custom-server@c47de3a

Current vs. Expected behavior

Expected:

  1. I create a recent NextJS project (14.1.4) using a recent Node version (v20.12)
  2. I want to deploy my app using Docker, therefore I use the output: "standalone" configuration in next.config.js
  3. I want to use some logging middlewares, therefore I use a custom server.js
  4. When I run npm run build and copy my custom server code to the build dir, the app is properly built and the file is properly copied
  5. When requiring next from server.js, all the dependencies are present and the server starts

Actual:

  1. 1-4 are the same as expected
  2. .next/standalone/node_modules/next/dist/compiled/webpack/build5.js does not exists in the built app
  3. When requiring next from server.js, I'm getting the error below because webpack tries to require build5.js
> node .next/standalone/custom-server.js

node:internal/modules/cjs/loader:1143
  const err = new Error(message);
              ^

Error: Cannot find module './bundle5'
Require stack:
- /Users/maxime/workspace/issue-bundle5-nextjs/.next/standalone/node_modules/next/dist/compiled/webpack/webpack.js
- /Users/maxime/workspace/issue-bundle5-nextjs/.next/standalone/node_modules/next/dist/server/config-utils.js
- /Users/maxime/workspace/issue-bundle5-nextjs/.next/standalone/node_modules/next/dist/server/config.js
- /Users/maxime/workspace/issue-bundle5-nextjs/.next/standalone/node_modules/next/dist/server/next.js
- /Users/maxime/workspace/issue-bundle5-nextjs/.next/standalone/custom-server.js
    at Module._resolveFilename (node:internal/modules/cjs/loader:1143:15)
    at /Users/maxime/workspace/issue-bundle5-nextjs/.next/standalone/node_modules/next/dist/server/require-hook.js:55:36
    at Module._load (node:internal/modules/cjs/loader:984:27)
    at Module.require (node:internal/modules/cjs/loader:1231:19)
    at mod.require (/Users/maxime/workspace/issue-bundle5-nextjs/.next/standalone/node_modules/next/dist/server/require-hook.js:65:28)
    at require (node:internal/modules/helpers:179:18)
    at exports.init (/Users/maxime/workspace/issue-bundle5-nextjs/.next/standalone/node_modules/next/dist/compiled/webpack/webpack.js:24:28)
    at loadWebpackHook (/Users/maxime/workspace/issue-bundle5-nextjs/.next/standalone/node_modules/next/dist/server/config-utils.js:18:5)
    at loadConfig (/Users/maxime/workspace/issue-bundle5-nextjs/.next/standalone/node_modules/next/dist/server/config.js:642:46)
    at initialize (/Users/maxime/workspace/issue-bundle5-nextjs/.next/standalone/node_modules/next/dist/server/lib/router-server.js:55:46) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [
    '/Users/maxime/workspace/issue-bundle5-nextjs/.next/standalone/node_modules/next/dist/compiled/webpack/webpack.js',
    '/Users/maxime/workspace/issue-bundle5-nextjs/.next/standalone/node_modules/next/dist/server/config-utils.js',
    '/Users/maxime/workspace/issue-bundle5-nextjs/.next/standalone/node_modules/next/dist/server/config.js',
    '/Users/maxime/workspace/issue-bundle5-nextjs/.next/standalone/node_modules/next/dist/server/next.js',
    '/Users/maxime/workspace/issue-bundle5-nextjs/.next/standalone/custom-server.js'
  ]
}

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 23.1.0: Mon Oct  9 21:27:24 PDT 2023; root:xnu-10002.41.9~6/RELEASE_ARM64_T6000
Binaries:
  Node: 20.12.0
  npm: 10.5.0
  Yarn: N/A
  pnpm: N/A
Relevant Packages:
  next: 14.1.4
  eslint-config-next: N/A
  react: 18.2.0
  react-dom: 18.2.0
  typescript: N/A
Next.js Config:
  output: standalone

Which area(s) are affected? (Select all that apply)

Standalone mode (output: "standalone")

Which stage(s) are affected? (Select all that apply)

next start (local)

Additional context

A workaround I found is to disable standalone output.
That probably disables tree shaking and relies on the complete node_modules directory.
A big drawback is that it makes a heavy docker image.

@maximelebastard maximelebastard added the bug Issue was opened via the bug report template. label Apr 3, 2024
@github-actions github-actions bot added the Output (export/standalone) Related to the the output option in `next.config.js`. label Apr 3, 2024
@maximelebastard maximelebastard changed the title Custom server is not usable anymore in production Missing webpack dependency when using output standalone + custom server Apr 3, 2024
@cs-miller

This comment has been minimized.

@clementzhao
Copy link

I have same issue. And I found the server.js which compiled with standalone can works. So I just copy these 2lines, and my custom server.js also works fine.

const nextConfig = {which from compiled server.js}
process.env.__NEXT_PRIVATE_STANDALONE_CONFIG = JSON.stringify(nextConfig)

@hi-zp
Copy link

hi-zp commented Apr 29, 2024

Here's my code, and while it works successfully, I'm not sure it's going to be a hidden problem

import { createServer } from 'node:http';
import { parse } from 'node:url';
import NextServer from 'next/dist/server/next-server';
// @ts-ignore
import { config } from './.next/required-server-files.json';
import { NextConfig } from 'next';

const port = parseInt(process.env.PORT || '9000', 10);
const hostname = '0.0.0.0';
const dev = process.env.NODE_ENV !== 'production';

const app = new NextServer({
  hostname: 'localhost',
  port,
  dir: process.cwd(),
  dev,
  conf: {
    ...(config as NextConfig),
  },
});

const handle = app.getRequestHandler();

app.prepare().then(() => {
  createServer((req, res) => {
    try {
      const parsedUrl = parse(req.url!, true);
     handle(req, res, parsedUrl);
    } catch (err) {
      console.error('Error occurred handling', req.url, err);
      res.statusCode = 500;
      res.end('internal server error');
    }
  })
    .once('error', (err) => {
      logger.error(err);
      process.exit(1);
    })
    .listen(port, () => {
      console.log(
        `> Server listening at http://${hostname}:${port} as ${
          dev ? 'development' : process.env.NODE_ENV
        }`,
      );
    });
});

@wq93
Copy link

wq93 commented Apr 30, 2024

I've met, too, frustrating

Node.js v18.20.2
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
yarn run v1.22.19
$ NODE_ENV=production node ./server/main.js
node:internal/modules/cjs/loader:1140
  const err = new Error(message);
              ^

Error: Cannot find module './bundle5'
Require stack:

@yunsii
Copy link
Contributor

yunsii commented Jul 4, 2024

Already 3 months passed, there is still no any progress? 🫠

@yunsii

This comment has been minimized.

@nectoscorp
Copy link

nectoscorp commented Jul 15, 2024

I confirmed that this works for me: #64031 (comment)
So AWS lambda, I am using the following to extract the JSON:
sed -n 12p .next/standalone/server.js | cut -c 20-

then require it inside my lambda handler file.

If I had more time I will figure out which particular parameter in the config made it work by commenting them out one at a time.

@yunsii
Copy link
Contributor

yunsii commented Jul 16, 2024

I have same issue. And I found the server.js which compiled with standalone can works. So I just copy these 2lines, and my custom server.js also works fine.

const nextConfig = {which from compiled server.js}
process.env.__NEXT_PRIVATE_STANDALONE_CONFIG = JSON.stringify(nextConfig)

Thanks @nectoscorp

After I tested, it works 😂

@nectoscorp
Copy link

nectoscorp commented Jul 16, 2024

I wish the nextConfig json was just saved on a file in like .next/standalone/next.config.json so we don't have to resort to these hacks. But obviously, the best is solution is to find out why bundle5 couldn't be found.

@Brandawg93
Copy link

Having the same issue. This seems to work well for me to allow for both local dev development and docker deployment:

const dev = process.env.NODE_ENV !== 'production'

if (!dev) {
  // eslint-disable-next-line @typescript-eslint/no-require-imports
  const { config } = require('./.next/required-server-files.json')
  process.env.__NEXT_PRIVATE_STANDALONE_CONFIG = JSON.stringify(config)
}

@flawnn
Copy link

flawnn commented Sep 25, 2024

Having the same issue. This seems to work well for me to allow for both local dev development and docker deployment:

const dev = process.env.NODE_ENV !== 'production'

if (!dev) {
  // eslint-disable-next-line @typescript-eslint/no-require-imports
  const { config } = require('./.next/required-server-files.json')
  process.env.__NEXT_PRIVATE_STANDALONE_CONFIG = JSON.stringify(config)
}

The ES6-conform version:

import("./.next/required-server-files.json")
        .then(({ default: { config } }) => {
        process.env.__NEXT_PRIVATE_STANDALONE_CONFIG = JSON.stringify(config);
        const app = next({ dev });
        return app.prepare().then(() => startServer(app) // startup func);
    })
        .catch((error) => {
        console.error("Failed to load required-server-files.json:", error);
        process.exit(1);
    });

@SujithPriyamRajan
Copy link

I have the same issue but surprisingly in PM2 as local & VM's was working fine

Can anyone summarize why this issue is ??

/** @type {import('next').NextConfig} */

const nextConfig = {
    output: 'standalone',
    typescript: {
        ignoreBuildErrors: true
    },
    images: { unoptimized: true },
    experimental: {
        serverActions: {
            serverActions: true
        },
        missingSuspenseWithCSRBailout: false
    },
    distDir: 'out',
    rewrites: async () => {
        return [
            {
                source: '/_next/static/:path*',
                destination: '/static/:path*'
            }
        ];
    }
};
export default nextConfig;

@aczekajski
Copy link

I found a universal way if adding missing dependencies to standalone output that I guess can also be used for custom server.

You can have a look here:
#66327 (comment)

@MJez29
Copy link
Contributor

MJez29 commented Nov 19, 2024

I also ran into this issue and came up with the exact same fix

I put up a PR to fix this in next.js: #72966

gaojude pushed a commit that referenced this issue Nov 19, 2024
## Fixing a bug

### Related issues

fixes #64031

### Why is this change needed

Per the Next.js
[docs](https://nextjs.org/docs/pages/api-reference/next-config-js/output)

> Next.js' production server is also traced for its needed files and
output at .next/next-server.js.nft.json which can be leveraged in
production.

When I tried doing this my [custom
server](https://nextjs.org/docs/pages/building-your-application/configuring/custom-server)
would crash on startup because of this codepath


https://github.com/vercel/next.js/blob/canary/packages/next/src/server/config.ts#L1022

My first attempt at fixing this involved changing

```
if (!process.env.__NEXT_PRIVATE_STANDALONE_CONFIG) {
```

to

```
if (phase === PHASE_PRODUCTION_SERVER) {
```

but this is not guaranteed to work because the next.config.js and it's
required dependencies may not be present causing the server to use the
default config

The best solution is to mimic standalone mode as closely as possible

### What does this change do

This change allows a custom server running in production with only
required files to pass in a preloaded next config (most likely from
`required-server-files.json`)

This is very similar to how the [standalone server
works](https://github.com/vercel/next.js/blob/bc49287063d6afd50a7361566b14f1ab6c26b136/packages/next/src/build/utils.ts#L2142)

### Testing

I'd like to get an initial round of feedback from the next team before I
dive into writing an integration test. I patched nextjs in my repo and
this solution worked
@gaojude gaojude reopened this Nov 20, 2024
wyattjoh pushed a commit that referenced this issue Nov 28, 2024
## Fixing a bug

### Related issues

fixes #64031

### Why is this change needed

Per the Next.js
[docs](https://nextjs.org/docs/pages/api-reference/next-config-js/output)

> Next.js' production server is also traced for its needed files and
output at .next/next-server.js.nft.json which can be leveraged in
production.

When I tried doing this my [custom
server](https://nextjs.org/docs/pages/building-your-application/configuring/custom-server)
would crash on startup because of this codepath


https://github.com/vercel/next.js/blob/canary/packages/next/src/server/config.ts#L1022

My first attempt at fixing this involved changing

```
if (!process.env.__NEXT_PRIVATE_STANDALONE_CONFIG) {
```

to

```
if (phase === PHASE_PRODUCTION_SERVER) {
```

but this is not guaranteed to work because the next.config.js and it's
required dependencies may not be present causing the server to use the
default config

The best solution is to mimic standalone mode as closely as possible

### What does this change do

This change allows a custom server running in production with only
required files to pass in a preloaded next config (most likely from
`required-server-files.json`)

This is very similar to how the [standalone server
works](https://github.com/vercel/next.js/blob/bc49287063d6afd50a7361566b14f1ab6c26b136/packages/next/src/build/utils.ts#L2142)

### Testing

I'd like to get an initial round of feedback from the next team before I
dive into writing an integration test. I patched nextjs in my repo and
this solution worked
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Issue was opened via the bug report template. Output (export/standalone) Related to the the output option in `next.config.js`.
Projects
None yet
Development

Successfully merging a pull request may close this issue.