Nx: [Feature Request] Next.js custom server support

Created on 9 Oct 2019  路  16Comments  路  Source: nrwl/nx

Desired Behavior

@nrwl/next would support the custom server and routing feature of Next.js. This inevitably ties in with #1895 as well.

Current Behavior

We are limited to modifying pages.

Context

nx report just returns with Project target does not exist., but:

  • @nrwl/cli v8.6.0
  • @nrwl/next v8.6.0
  • @nrwl/workspace v8.6.0
nextjs feature

Most helpful comment

Nice, @elliottsj. I think TS and importing from the monorepo are must-have features of a custom server implementation, so hopefully your RFC gets some traction. 馃

All 16 comments

Here's an example that hopefully helps a bit:
https://github.com/bbasinsk/nx-next-custom-server/tree/master.

There's a couple changes to make from the default Next app:

  • Use the @nrwl/node:execute builder rather than @nrwl/next:dev-server with a custom buildTarget.
    Example

  • Make sure to check to not use the @zeit/next-css (or less, sass, or stylus) plugin when building with @nrwl/next:build (or you'll get a "Didn't get a result from child compiler" error from webpack).
    Example

Might be able to help #1895 too since it has a next.config.js.

@bbasinsk Thanks for the response! I tried your example but ran into a problem when taking it a step further towards making it a "real world" app. I generated a React component library in the same workspace (nx g @nrwl/react:lib ui) but was unable to import components from it in next-app:

Module not found: Can't resolve '@nx-workspace/ui' in 'nx-next-custom-server\apps\next-app\pages'

(Note: TypeScript and ESLint both seem to think it's fine, as there are no type errors found nor any module resolution lint errors, but serving fails with the above error.)

Prior to seeing your example, I had attempted to create an Express app (nx g @nrwl/express:app next-app) and turn that into a Next.js app with custom server, but I ran into the exact same problem there too. So maybe it's got something to do with @nrwl/node:build?

@wKovacs64 Oh interesting. I just assumed that would work. But you're right, I'm running into the same wall here.

I had the same problem when tried @bbasinsk solution. From the error logs it seems that it doesn't even look into the ./libs/ folder for the component for some reason. Maybe @vsavkin can take a look at this issue and give some general directions where to dig? I'm happy to help with debugging or opening a pr for this issue but I think it would save me a lot of time if somebody who knows how resolving of those dependancies work in the first place could leave a comment :)

Based on this comment https://github.com/nrwl/nx/issues/1895#issuecomment-546536673 I've found out that simply adding tsconfig-paths-webpack-plugin to your custom next.config.js makes things work. But there is another problem with this approach and that is if you build a production build it will not use your custom configuration, it will use its default config from utils provided by nx and this build will not include your custom server file of course. Also in this configuration dev build and prod build are output to the same folder and mix up, but it's easy to separate those two.

Yep, there are issues with every workaround I've explored. I think first-class support is going to be the way to go.

It appears that @nrwl/next has custom server support now: https://github.com/nrwl/nx/blob/9c50569c55090d5ec7d16d97ac9a829de5aea9b1/packages/next/src/builders/dev-server/dev-server.impl.ts#L52

In your serve config, you can pass a customServerPath to a Node.js module:

"serve": {
  "builder": "@nrwl/next:dev-server",
  "options": {
    "buildTarget": "myapp:build",
    "dev": true,
    "port": 3001,
    "customServerPath": "server.js"
  }
},

This module should export a function which accepts two arguments and returns a promise which resolve when the server is ready: (nextApp, settings) => Promise<void>. This is where it's executed: https://github.com/nrwl/nx/blob/9c50569c55090d5ec7d16d97ac9a829de5aea9b1/packages/next/src/builders/dev-server/dev-server.impl.ts#L52

However, the custom server cannot be written in TypeScript at the moment; it must be able to execute directly in Node.js. This also means the server module cannot import other packages in the monorepo, because Nx relies on the tsconfig.json "paths" config to resolve other packages.

This feels like a gap in Nx's support of Next.js. Is there a plan to add support for a Next.js TypeScript custom server?

Here is a proof-of-concept implementing a custom TypeScript server: https://github.com/nrwl/nx/pull/2227

Would love to get some feedback on this

Nice, @elliottsj. I think TS and importing from the monorepo are must-have features of a custom server implementation, so hopefully your RFC gets some traction. 馃

Is this issue a priority? Any movement?

@zenVentzi this feature already is in (minus TypeScript support)

Here is an example of how to implement.

https://gist.github.com/stramel/57483a68559dca2c6471b3170a28042f

@stramel is there some workaround for importing typescript files? Maybe somehow make sure they compile to js first before they are imported in the server.js file? (EDIT: use esm package, then require(./myFile.ts))

Also, how can we pass arguments to node? E.g. there are .js files with es6 modules, by passing some extra args we can at least use these files. Node v.13 is not an option for now.

EDIT: the es6 modules are not a good enough example since we can use the esm package for that.
EDIT1: Actually this really is more complicated than it needs to be. Even with the esm package. Official support will be very appreciated!

@stramel So as of now, do we have to run nx serve in production? I think there should be only dist/apps/<appname> folder that is deployed to the host.

I tried to change the scripts in dist/apps/<appname>/package.json to "start": "NODE_ENV=production node server.js" but nx build create and replace package.json automatically and AFAIK I can't replace file package.json with fileReplacements option.

@stramel Your example works fine when serving but will lack express functionality when building for production. Any idea on how to fix that? A workaround I did for now was to manually add missing functionality from Express source code

I just published an NPM package which is a good solution for this problem.

https://www.npmjs.com/package/nx-next-server

You can create a Nx app which acts as a server for a Next.js app in your workspace. This allows you to even import libs from your workspace.

Hope it helps someone!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

olakara picture olakara  路  3Comments

zpydee picture zpydee  路  3Comments

vimalraj-a picture vimalraj-a  路  3Comments

jon301 picture jon301  路  3Comments

Svancara picture Svancara  路  3Comments