Skip to content

Commit

Permalink
feat(nx): nextjs custom server support
Browse files Browse the repository at this point in the history
  • Loading branch information
miguelramos authored and vsavkin committed Nov 13, 2019
1 parent 791c3f2 commit 44d45d3
Show file tree
Hide file tree
Showing 12 changed files with 205 additions and 14 deletions.
6 changes: 6 additions & 0 deletions docs/angular/api-next/builders/dev-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ Type: `string`

Target which builds the application

### customServerPath

Type: `string`

Use a custom server script

### dev

Default: `true`
Expand Down
6 changes: 6 additions & 0 deletions docs/angular/api-next/schematics/application.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ Type: `boolean`

Use pascal case component file name (e.g. App.tsx)

### server

Type: `string`

The server script path to be used with next.

### skipFormat

Default: `false`
Expand Down
6 changes: 6 additions & 0 deletions docs/react/api-next/builders/dev-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ Type: `string`

Target which builds the application

### customServerPath

Type: `string`

Use a custom server script

### dev

Default: `true`
Expand Down
6 changes: 6 additions & 0 deletions docs/react/api-next/schematics/application.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ Type: `boolean`

Use pascal case component file name (e.g. App.tsx)

### server

Type: `string`

The server script path to be used with next.

### skipFormat

Default: `false`
Expand Down
6 changes: 6 additions & 0 deletions docs/web/api-next/builders/dev-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ Type: `string`

Target which builds the application

### customServerPath

Type: `string`

Use a custom server script

### dev

Default: `true`
Expand Down
6 changes: 6 additions & 0 deletions docs/web/api-next/schematics/application.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ Type: `boolean`

Use pascal case component file name (e.g. App.tsx)

### server

Type: `string`

The server script path to be used with next.

### skipFormat

Default: `false`
Expand Down
2 changes: 1 addition & 1 deletion packages/next/collection.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "nx/nest",
"name": "nx/next",
"version": "0.1",
"extends": ["@nrwl/react"],
"schematics": {
Expand Down
52 changes: 40 additions & 12 deletions packages/next/src/builders/dev-server/dev-server.impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
PHASE_PRODUCTION_SERVER
} from 'next-server/constants';
import startServer from 'next/dist/server/lib/start-server';
import NextServer from 'next/dist/server/next-dev-server';
import * as path from 'path';
import { from, Observable, of } from 'rxjs';
import { switchMap, concatMap } from 'rxjs/operators';
Expand All @@ -26,10 +27,31 @@ export interface NextBuildBuilderOptions extends JsonObject {
staticMarkup: boolean;
quiet: boolean;
buildTarget: string;
customServerPath: string;
}

export interface NextServerOptions {
dev: string;
dir: string;
staticMarkup: boolean;
quiet: boolean;
conf: any;
port: number;
path: string;
}

export default createBuilder<NextBuildBuilderOptions>(run);

function defaultServer(settings: NextServerOptions) {
return startServer(settings, settings.port).then(app => app.prepare());
}

function customServer(settings: NextServerOptions) {
const nextApp = new NextServer(settings);

return require(path.resolve(settings.dir, settings.path))(nextApp, settings);
}

function run(
options: NextBuildBuilderOptions,
context: BuilderContext
Expand All @@ -46,25 +68,31 @@ function run(
return from(context.getTargetOptions(buildTarget)).pipe(
concatMap((buildOptions: any) => {
const root = path.resolve(context.workspaceRoot, buildOptions.root);

const config = prepareConfig(
context.workspaceRoot,
buildOptions.root,
buildOptions.outputPath,
options.dev ? PHASE_DEVELOPMENT_SERVER : PHASE_PRODUCTION_SERVER
);

return from(
startServer(
{
dev: options.dev,
dir: root,
staticMarkup: options.staticMarkup,
quiet: options.quiet,
conf: config
} as any,
options.port
).then(app => app.prepare())
).pipe(
const settings = {
dev: options.dev
? PHASE_DEVELOPMENT_SERVER
: PHASE_PRODUCTION_SERVER,
dir: root,
staticMarkup: options.staticMarkup,
quiet: options.quiet,
conf: config,
port: options.port,
path: options.customServerPath
};

const server = options.customServerPath
? customServer
: defaultServer;

return from(server(settings)).pipe(
switchMap(
e =>
new Observable<BuilderOutput>(obs => {
Expand Down
5 changes: 5 additions & 0 deletions packages/next/src/builders/dev-server/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@
"type": "boolean",
"description": "Hide error messages containing server information.",
"default": false
},
"customServerPath": {
"type": "string",
"description": "Use a custom server script",
"default": null
}
},
"required": []
Expand Down
118 changes: 117 additions & 1 deletion packages/next/src/schematics/application/application.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { join, JsonObject, normalize, Path } from '@angular-devkit/core';
import {
join,
JsonObject,
normalize,
Path,
dirname
} from '@angular-devkit/core';
import {
apply,
chain,
Expand Down Expand Up @@ -60,6 +66,7 @@ export default function(schema: Schema): Rule {
extraPackageDeps: extraEslintDependencies
}),
createApplicationFiles(options),
createNextServerFiles(options),
updateNxJson(options),
addProject(options),
addCypress(options),
Expand All @@ -71,6 +78,107 @@ export default function(schema: Schema): Rule {
};
}

function createNextServerFiles(options: NormalizedSchema) {
return (host: Tree) => {
if (options.server) {
const directory = dirname(join(options.appProjectRoot, options.server));

host.create(
join(options.appProjectRoot, options.server),

This comment has been minimized.

Copy link
@dmitriy-baltak

dmitriy-baltak Nov 26, 2019

You are using options.server both as file name and path, something goes wrong here, in the end if you pass path to options.server - it's not created, file without an extension is created instead.

This comment has been minimized.

Copy link
@dmitriy-baltak

dmitriy-baltak Nov 26, 2019

Also options.server is not used for the prod server.js file, it's created in the root folder of the project for some reason

`
// @ts-check
'use strict';
/**
* @typedef {import('http').Server} Server
* @typedef {import('next/dist/server/next-dev-server').default} DevServer
*/
const express = require('express');
/**
* @param {DevServer} app
* @param {{dev: string; dir: string; staticMarkup: boolean; quiet: boolean; conf: any; port: number;}} options
* @returns {Promise<Server>}
*/
module.exports = async function nextServer(app, options) {
const handle = app.getRequestHandler();
const expressApp = express();
await app.prepare();
/**
* @returns {Promise<Server>}
*/
return new Promise((resolve, reject) => {
expressApp.all('*', (req, res) => {
return handle(req, res);
});
const server = expressApp.listen(options.port, (err) => {
err ? reject(err) : resolve(server);
});
});
}
`
);

host.create(
join(directory, 'server.js'),
`
// @ts-check
'use strict';
/**
* Production Nextjs custom server
*
* Usage: run this script with node
* Adjust dir option for your serve/deploy config
*
* node server.js
*/
/**
* @typedef {import('next-server/dist/server/next-server').default} Server
*/
const NextServer = require('next-server/dist/server/next-server').default;
const express = require('express');
const nextApp = new NextServer({
dir: './dist/apps/<%= name %>',
staticMarkup: false,
quiet: false,
conf: {
distDir: '.'
}
});
const serve = async () => {
const handle = nextApp.getRequestHandler();
const expressApp = express();
await nextApp.prepare();
return new Promise((resolve, reject) => {
expressApp.all('*', (req, res) => {
return handle(req, res);
});
const server = expressApp.listen(4200, err => {
err ? reject(err) : resolve(server);
});
});
}
serve().then(server => console.log('Server is running on port 4200'));
`
);
}
};
}

function createApplicationFiles(options: NormalizedSchema): Rule {
return mergeWith(
apply(url(`./files`), [
Expand Down Expand Up @@ -101,6 +209,7 @@ function updateNxJson(options: NormalizedSchema): Rule {
function addProject(options: NormalizedSchema): Rule {
return updateWorkspaceInTree(json => {
const architect: { [key: string]: any } = {};
const { server } = options;

architect.build = {
builder: '@nrwl/next:build',
Expand All @@ -123,6 +232,13 @@ function addProject(options: NormalizedSchema): Rule {
}
};

if (server) {
architect.serve.options = {
...architect.serve.options,
customServerPath: options.server
};
}

architect.export = {
builder: '@nrwl/next:export',
options: {
Expand Down
1 change: 1 addition & 0 deletions packages/next/src/schematics/application/schema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Linter } from '@nrwl/workspace';
export interface Schema {
name: string;
style?: string;
server?: string;
skipFormat: boolean;
directory?: string;
tags?: string;
Expand Down
5 changes: 5 additions & 0 deletions packages/next/src/schematics/application/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@
]
}
},
"server": {
"description": "The server script path to be used with next.",
"type": "string",
"default": null
},
"linter": {
"description": "The tool to use for running lint checks.",
"type": "string",
Expand Down

0 comments on commit 44d45d3

Please sign in to comment.