vercel / next.js

The React Framework
https://nextjs.org
MIT License
125.84k stars 26.85k forks source link

Custom server config not working #60040

Open BenjaminToby opened 9 months ago

BenjaminToby commented 9 months ago

Link to the code that reproduces this issue

https://codesandbox.io/p/devbox/next-js-custom-server-bug-6z8fhc

To Reproduce

  1. Create a basic next js application by running npx create-next-app@latest.
  2. cd into the new directory and add a basic server.js file in the root directory with these content:
    
    const { createServer } = require("http");
    const { parse } = require("url");
    const fs = require("fs");
    const path = require("path");

const next = require("next");

const dev = process.env.NODE_ENV !== "production"; const hostname = "localhost"; const port = 3600;

const app = next({ dev, hostname, port, conf: { distDir: ".custom_dist", } });

const handle = app.getRequestHandler();

app.prepare() .then(() => { const server = createServer(async (req, res) => { try { const parsedUrl = parse(req.url || "", true); const { pathname, query } = parsedUrl;

            await handle(req, res, parsedUrl);
        } catch (err) {
            console.error("Error occurred handling", req.url, err);
            res.statusCode = 500;
            res.end("internal server error");
        }
    });

    server.on("error", (err) => {
        console.error("⚠️ SERVER ERROR =>", err.message);
    });

    server.listen(port, () => {
        console.log(`> Ready on http://${hostname}:${port}`);
    });
})
.catch((error) => {
    console.log(error);
});
3. Run `node server.js` to start the development server.

### Current vs. Expected behavior

### Expectation
When the development server is started, the dist directory should be loaded from the `conf` property in the `next` function argument, and there should be a new folder in the root directory named `.custom_dist`.

### Current Behavior
The default `.next` directory is used instead of the specified `.custom_dist` directory. 

### Verify canary release

- [X] I verified that the issue exists in the latest Next.js canary release

### Provide environment information

```bash
Operating System:
  Platform: linux
  Arch: x64
  Version: #1 SMP PREEMPT_DYNAMIC Sun Aug  6 20:05:33 UTC 2023
Binaries:
  Node: 20.9.0
  npm: 9.8.1
  Yarn: 1.22.19
  pnpm: 8.10.2
Relevant Packages:
  next: 14.0.4
  eslint-config-next: 14.0.4
  react: 18.2.0
  react-dom: 18.2.0
  typescript: 5.3.3
Next.js Config:
  output: N/A

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

Not sure

Additional context

This bug appeared with Next 13. I'm currently running Next 12 on my apps to avoid this bug.

Bahlaouane-Hamza commented 9 months ago

You need to also add distDir: '.custom_dist'to your next.config.js This works for me

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  distDir: '.custom_dist',
}

module.exports = nextConfig
BenjaminToby commented 9 months ago

@Bahlaouane-Hamza thanks for the suggestion. But the bug still persists. The Next JS documentation provides the option for a conf object which doesn't work in Next 13+, and this should be fixed.

In addition, there are scenarios where the next.config.js file isn't sufficient. For example: in one of my projects I'm loading the config object from a JSON file: this JSON file is tweaked during every build to generate a new build directory(for versioning purposes), and the server.js file picks up the new build directory automatically on every new build: of course it can't pick up the new directory in Next 13+ because the conf variable is broken.

molily commented 5 months ago

Here's what happens as far as I understand:

createServer – which is what you get with require('next') – instantiates NextCustomServer. Its superclass NextServer does save the passed config in this.options.conf:

https://github.com/vercel/next.js/blob/c1f8d9317588e51a8a31240f6add36b5f2c9f9bf/packages/next/src/server/next.ts#L71

But does not pass it through to the router server. So it's not used eventually.

https://github.com/vercel/next.js/blob/c1f8d9317588e51a8a31240f6add36b5f2c9f9bf/packages/next/src/server/next.ts#L274 https://github.com/vercel/next.js/blob/c1f8d9317588e51a8a31240f6add36b5f2c9f9bf/packages/next/src/server/lib/start-server.ts#L49 https://github.com/vercel/next.js/blob/c1f8d9317588e51a8a31240f6add36b5f2c9f9bf/packages/next/src/server/lib/router-server.ts#L63

The router server calls loadConfig without passing a customConfig/rawConfig:

https://github.com/vercel/next.js/blob/c1f8d93/packages/next/src/server/lib/router-server.ts#L82

So loadConfig always reads the next.config.js file:

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

So currently, the passed config is not used and next.config.js is currently only the source of truth.