From fd18b5edecceb2186780edc2ca1be36caffe967d Mon Sep 17 00:00:00 2001 From: Jason Jean Date: Tue, 23 Feb 2021 11:39:20 -0500 Subject: [PATCH] feat(react): migrate next builders to devkit (#4861) --- e2e/workspace/src/create-nx-workspace.test.ts | 2 + packages/next/.eslintrc.json | 2 +- packages/next/builders.json | 32 ++++-- packages/next/package.json | 4 +- .../next/src/builders/build/build.impl.ts | 38 ------- .../next/src/builders/export/export.impl.ts | 55 --------- .../next/src/builders/server/server.impl.ts | 106 ------------------ .../build/build.impl.spec.ts | 24 ++-- .../next/src/executors/build/build.impl.ts | 31 +++++ packages/next/src/executors/build/compat.ts | 5 + .../build/lib/create-next-config-file.ts | 12 +- .../build/lib/create-package-json.ts | 26 +++-- .../{builders => executors}/build/schema.json | 1 + packages/next/src/executors/export/compat.ts | 5 + .../next/src/executors/export/export.impl.ts | 52 +++++++++ .../export/schema.json | 1 + packages/next/src/executors/server/compat.ts | 5 + .../server/lib/custom-server.ts | 0 .../server/lib/default-server.ts | 0 .../server/schema.json | 1 + .../next/src/executors/server/server.impl.ts | 98 ++++++++++++++++ packages/next/src/utils/config.spec.ts | 3 +- packages/next/src/utils/config.ts | 7 +- packages/next/src/utils/testing.ts | 25 ----- packages/next/src/utils/types.ts | 10 +- 25 files changed, 275 insertions(+), 270 deletions(-) delete mode 100644 packages/next/src/builders/build/build.impl.ts delete mode 100644 packages/next/src/builders/export/export.impl.ts delete mode 100644 packages/next/src/builders/server/server.impl.ts rename packages/next/src/{builders => executors}/build/build.impl.spec.ts (72%) create mode 100644 packages/next/src/executors/build/build.impl.ts create mode 100644 packages/next/src/executors/build/compat.ts rename packages/next/src/{builders => executors}/build/lib/create-next-config-file.ts (57%) rename packages/next/src/{builders => executors}/build/lib/create-package-json.ts (79%) rename packages/next/src/{builders => executors}/build/schema.json (98%) create mode 100644 packages/next/src/executors/export/compat.ts create mode 100644 packages/next/src/executors/export/export.impl.ts rename packages/next/src/{builders => executors}/export/schema.json (97%) create mode 100644 packages/next/src/executors/server/compat.ts rename packages/next/src/{builders => executors}/server/lib/custom-server.ts (100%) rename packages/next/src/{builders => executors}/server/lib/default-server.ts (100%) rename packages/next/src/{builders => executors}/server/schema.json (98%) create mode 100644 packages/next/src/executors/server/server.impl.ts delete mode 100644 packages/next/src/utils/testing.ts diff --git a/e2e/workspace/src/create-nx-workspace.test.ts b/e2e/workspace/src/create-nx-workspace.test.ts index 1f1ad56d01..4ec79d83d1 100644 --- a/e2e/workspace/src/create-nx-workspace.test.ts +++ b/e2e/workspace/src/create-nx-workspace.test.ts @@ -68,6 +68,8 @@ describe('create-nx-workspace', () => { style: 'css', appName, }); + + expectNoAngularDevkit(); }); it('should be able to create an web-components workspace', () => { diff --git a/packages/next/.eslintrc.json b/packages/next/.eslintrc.json index b6ddf614e6..5c720ddb20 100644 --- a/packages/next/.eslintrc.json +++ b/packages/next/.eslintrc.json @@ -7,7 +7,7 @@ "excludedFiles": ["./src/migrations/**"], "rules": { "no-restricted-imports": [ - "warn", + "error", "@nrwl/workspace", "@angular-devkit/core", "@angular-devkit/schematics", diff --git a/packages/next/builders.json b/packages/next/builders.json index 4e07141067..65e5f37495 100644 --- a/packages/next/builders.json +++ b/packages/next/builders.json @@ -1,19 +1,35 @@ { - "$schema": "@angular-devkit/architect/src/builders-schema.json", - "builders": { + "executors": { "build": { - "implementation": "./src/builders/build/build.impl", - "schema": "./src/builders/build/schema.json", + "implementation": "./src/executors/build/build.impl", + "schema": "./src/executors/build/schema.json", "description": "Build a Next.js app" }, "server": { - "implementation": "./src/builders/server/server.impl", - "schema": "./src/builders/server/schema.json", + "implementation": "./src/executors/server/server.impl", + "schema": "./src/executors/server/schema.json", "description": "Serve a Next.js app" }, "export": { - "implementation": "./src/builders/export/export.impl", - "schema": "./src/builders/export/schema.json", + "implementation": "./src/executors/export/export.impl", + "schema": "./src/executors/export/schema.json", + "description": "Export a Next.js app. The exported application is located at dist/$outputPath/exported." + } + }, + "builders": { + "build": { + "implementation": "./src/executors/build/compat", + "schema": "./src/executors/build/schema.json", + "description": "Build a Next.js app" + }, + "server": { + "implementation": "./src/executors/server/compat", + "schema": "./src/executors/server/schema.json", + "description": "Serve a Next.js app" + }, + "export": { + "implementation": "./src/executors/export/compat", + "schema": "./src/executors/export/schema.json", "description": "Export a Next.js app. The exported application is located at dist/$outputPath/exported." } } diff --git a/packages/next/package.json b/packages/next/package.json index c6b9678ffa..0aa4112ea2 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -37,9 +37,7 @@ "@nrwl/jest": "*", "@nrwl/linter": "*", "@nrwl/web": "*", - "@angular-devkit/architect": "~0.1102.0", - "@angular-devkit/schematics": "~11.2.0", - "@angular-devkit/core": "~11.2.0", + "@nrwl/workspace": "*", "@svgr/webpack": "^5.4.0", "chalk": "4.1.0", "copy-webpack-plugin": "6.0.3", diff --git a/packages/next/src/builders/build/build.impl.ts b/packages/next/src/builders/build/build.impl.ts deleted file mode 100644 index 4a3b5f0c97..0000000000 --- a/packages/next/src/builders/build/build.impl.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { - BuilderContext, - BuilderOutput, - createBuilder, -} from '@angular-devkit/architect'; -import build from 'next/dist/build'; -import { PHASE_PRODUCTION_BUILD } from 'next/dist/next-server/lib/constants'; -import * as path from 'path'; -import { copySync } from 'fs-extra'; -import { from, Observable } from 'rxjs'; -import { concatMap, map, tap } from 'rxjs/operators'; -import { prepareConfig } from '../../utils/config'; -import { NextBuildBuilderOptions } from '../../utils/types'; -import { createPackageJson } from './lib/create-package-json'; -import { createNextConfigFile } from './lib/create-next-config-file'; -import { join } from 'path'; - -try { - require('dotenv').config(); -} catch (e) {} - -export default createBuilder(run); - -export function run( - options: NextBuildBuilderOptions, - context: BuilderContext -): Observable { - const root = path.resolve(context.workspaceRoot, options.root); - const config = prepareConfig(PHASE_PRODUCTION_BUILD, options, context); - return from(build(root, config as any)).pipe( - concatMap(() => from(createPackageJson(options, context))), - concatMap(() => from(createNextConfigFile(options, context))), - tap(() => { - copySync(join(root, 'public'), join(options.outputPath, 'public')); - }), - map(() => ({ success: true })) - ); -} diff --git a/packages/next/src/builders/export/export.impl.ts b/packages/next/src/builders/export/export.impl.ts deleted file mode 100644 index bf6f937a33..0000000000 --- a/packages/next/src/builders/export/export.impl.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { - BuilderContext, - BuilderOutput, - createBuilder, - scheduleTargetAndForget, - targetFromTargetString, -} from '@angular-devkit/architect'; -import exportApp from 'next/dist/export'; -import { PHASE_EXPORT } from 'next/dist/next-server/lib/constants'; -import * as path from 'path'; -import { from, Observable, of } from 'rxjs'; -import { concatMap, map } from 'rxjs/operators'; -import { prepareConfig } from '../../utils/config'; -import { - NextBuildBuilderOptions, - NextExportBuilderOptions, -} from '../../utils/types'; - -try { - require('dotenv').config(); -} catch (e) {} - -export default createBuilder(run); - -function run( - options: NextExportBuilderOptions, - context: BuilderContext -): Observable { - const buildTarget = targetFromTargetString(options.buildTarget); - const build$ = scheduleTargetAndForget(context, buildTarget); - - return build$.pipe( - concatMap((r) => { - if (!r.success) return of(r); - return from(context.getTargetOptions(buildTarget)).pipe( - concatMap((buildOptions: NextBuildBuilderOptions) => { - const root = path.resolve(context.workspaceRoot, buildOptions.root); - const config = prepareConfig(PHASE_EXPORT, buildOptions, context); - return from( - exportApp( - root, - { - statusMessage: 'Exporting', - silent: options.silent, - threads: options.threads, - outdir: `${buildOptions.outputPath}/exported`, - } as any, - config - ) - ).pipe(map(() => ({ success: true }))); - }) - ); - }) - ); -} diff --git a/packages/next/src/builders/server/server.impl.ts b/packages/next/src/builders/server/server.impl.ts deleted file mode 100644 index 1828c33584..0000000000 --- a/packages/next/src/builders/server/server.impl.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { - BuilderContext, - BuilderOutput, - createBuilder, - scheduleTargetAndForget, - targetFromTargetString, -} from '@angular-devkit/architect'; -import * as chalk from 'chalk'; -import * as fs from 'fs'; -import { - PHASE_DEVELOPMENT_SERVER, - PHASE_PRODUCTION_SERVER, -} from 'next/dist/next-server/lib/constants'; -import * as path from 'path'; -import { from, Observable, of, throwError } from 'rxjs'; -import { catchError, concatMap, switchMap, tap } from 'rxjs/operators'; -import { prepareConfig } from '../../utils/config'; -import { - NextBuildBuilderOptions, - NextServeBuilderOptions, - NextServer, - NextServerOptions, - ProxyConfig, -} from '../../utils/types'; -import { customServer } from './lib/custom-server'; -import { defaultServer } from './lib/default-server'; - -try { - require('dotenv').config(); -} catch (e) {} - -export default createBuilder(run); - -const infoPrefix = `[ ${chalk.dim(chalk.cyan('info'))} ] `; -const readyPrefix = `[ ${chalk.green('ready')} ]`; - -export function run( - options: NextServeBuilderOptions, - context: BuilderContext -): Observable { - const buildTarget = targetFromTargetString(options.buildTarget); - const baseUrl = `http://${options.hostname || 'localhost'}:${options.port}`; - - return from(context.getTargetOptions(buildTarget)).pipe( - concatMap((buildOptions: NextBuildBuilderOptions) => { - const root = path.resolve(context.workspaceRoot, buildOptions.root); - - const config = prepareConfig( - options.dev ? PHASE_DEVELOPMENT_SERVER : PHASE_PRODUCTION_SERVER, - buildOptions, - context - ); - - const settings: NextServerOptions = { - dev: options.dev, - dir: root, - staticMarkup: options.staticMarkup, - quiet: options.quiet, - conf: config, - port: options.port, - path: options.customServerPath, - hostname: options.hostname, - }; - - const server: NextServer = options.customServerPath - ? customServer - : defaultServer; - - // look for the proxy.conf.json - let proxyConfig: ProxyConfig; - const proxyConfigPath = options.proxyConfig - ? path.join(context.workspaceRoot, options.proxyConfig) - : path.join(root, 'proxy.conf.json'); - if (fs.existsSync(proxyConfigPath)) { - context.logger.info( - `${infoPrefix} found proxy configuration at ${proxyConfigPath}` - ); - proxyConfig = require(proxyConfigPath); - } - - return from(server(settings, proxyConfig)).pipe( - catchError((err) => { - if (options.dev) { - throw err; - } else { - throw new Error( - `Could not start production server. Try building your app with \`nx build ${context.target.project}\`.` - ); - } - }), - tap(() => { - context.logger.info(`${readyPrefix} on ${baseUrl}`); - }), - switchMap( - (e) => - new Observable((obs) => { - obs.next({ - baseUrl, - success: true, - }); - }) - ) - ); - }) - ); -} diff --git a/packages/next/src/builders/build/build.impl.spec.ts b/packages/next/src/executors/build/build.impl.spec.ts similarity index 72% rename from packages/next/src/builders/build/build.impl.spec.ts rename to packages/next/src/executors/build/build.impl.spec.ts index c03b2c62dd..04cd658dc4 100644 --- a/packages/next/src/builders/build/build.impl.spec.ts +++ b/packages/next/src/executors/build/build.impl.spec.ts @@ -1,8 +1,9 @@ -import { MockBuilderContext } from '@nrwl/workspace/testing'; +import { ExecutorContext } from '@nrwl/devkit'; + import * as build from 'next/dist/build'; -import { getMockContext } from '../../utils/testing'; + import { NextBuildBuilderOptions } from '../../utils/types'; -import { run } from './build.impl'; +import buildExecutor from './build.impl'; jest.mock('fs-extra'); jest.mock('next/dist/build'); @@ -13,12 +14,21 @@ jest.mock('./lib/create-package-json', () => { }); describe('Next.js Builder', () => { - let context: MockBuilderContext; + let context: ExecutorContext; let options: NextBuildBuilderOptions; beforeEach(async () => { - context = await getMockContext(); - + context = { + root: '/root', + cwd: '/root', + projectName: 'my-app', + targetName: 'build', + workspace: { + version: 2, + projects: {}, + }, + isVerbose: false, + }; options = { root: 'apps/wibble', outputPath: 'dist/apps/wibble', @@ -34,7 +44,7 @@ describe('Next.js Builder', () => { }); it('should call next build', async () => { - await run(options, context).toPromise(); + await buildExecutor(options, context); expect(build.default).toHaveBeenCalledWith( '/root/apps/wibble', diff --git a/packages/next/src/executors/build/build.impl.ts b/packages/next/src/executors/build/build.impl.ts new file mode 100644 index 0000000000..853cb45e03 --- /dev/null +++ b/packages/next/src/executors/build/build.impl.ts @@ -0,0 +1,31 @@ +import { ExecutorContext } from '@nrwl/devkit'; + +import build from 'next/dist/build'; +import { PHASE_PRODUCTION_BUILD } from 'next/dist/next-server/lib/constants'; + +import { join, resolve } from 'path'; +import { copySync } from 'fs-extra'; + +import { prepareConfig } from '../../utils/config'; +import { NextBuildBuilderOptions } from '../../utils/types'; +import { createPackageJson } from './lib/create-package-json'; +import { createNextConfigFile } from './lib/create-next-config-file'; + +try { + require('dotenv').config(); +} catch (e) {} + +export default async function buildExecutor( + options: NextBuildBuilderOptions, + context: ExecutorContext +) { + const root = resolve(context.root, options.root); + const config = prepareConfig(PHASE_PRODUCTION_BUILD, options, context); + await build(root, config as any); + createPackageJson(options, context); + createNextConfigFile(options, context); + + copySync(join(root, 'public'), join(options.outputPath, 'public')); + + return { success: true }; +} diff --git a/packages/next/src/executors/build/compat.ts b/packages/next/src/executors/build/compat.ts new file mode 100644 index 0000000000..477ba0be5f --- /dev/null +++ b/packages/next/src/executors/build/compat.ts @@ -0,0 +1,5 @@ +import { convertNxExecutor } from '@nrwl/devkit'; + +import buildExecutor from './build.impl'; + +export default convertNxExecutor(buildExecutor); diff --git a/packages/next/src/builders/build/lib/create-next-config-file.ts b/packages/next/src/executors/build/lib/create-next-config-file.ts similarity index 57% rename from packages/next/src/builders/build/lib/create-next-config-file.ts rename to packages/next/src/executors/build/lib/create-next-config-file.ts index 3b806fe913..b28948ae2b 100644 --- a/packages/next/src/builders/build/lib/create-next-config-file.ts +++ b/packages/next/src/executors/build/lib/create-next-config-file.ts @@ -1,15 +1,17 @@ +import { ExecutorContext } from '@nrwl/devkit'; + import { copyFileSync, existsSync } from 'fs'; import { join } from 'path'; -import { BuilderContext } from '@angular-devkit/architect'; + import { NextBuildBuilderOptions } from '../../../utils/types'; -export async function createNextConfigFile( +export function createNextConfigFile( options: NextBuildBuilderOptions, - context: BuilderContext + context: ExecutorContext ) { const nextConfigPath = options.nextConfig - ? join(context.workspaceRoot, options.nextConfig) - : join(context.workspaceRoot, options.root, 'next.config.js'); + ? join(context.root, options.nextConfig) + : join(context.root, options.root, 'next.config.js'); if (existsSync(nextConfigPath)) { copyFileSync(nextConfigPath, join(options.outputPath, 'next.config.js')); diff --git a/packages/next/src/builders/build/lib/create-package-json.ts b/packages/next/src/executors/build/lib/create-package-json.ts similarity index 79% rename from packages/next/src/builders/build/lib/create-package-json.ts rename to packages/next/src/executors/build/lib/create-package-json.ts index b3c425b423..65303b9eae 100644 --- a/packages/next/src/builders/build/lib/create-package-json.ts +++ b/packages/next/src/executors/build/lib/create-package-json.ts @@ -1,16 +1,22 @@ -import { BuilderContext } from '@angular-devkit/architect'; +import { ExecutorContext } from '@nrwl/devkit'; + import { writeFileSync } from 'fs'; import { join } from 'path'; -import { readJsonFile } from '@nrwl/workspace'; + import { createProjectGraph } from '@nrwl/workspace/src/core/project-graph'; -import { calculateProjectDependencies } from '@nrwl/workspace/src/utils/buildable-libs-utils'; +import { readJsonFile } from '@nrwl/workspace/src/utilities/fileutils'; +import { calculateProjectDependencies } from '@nrwl/workspace/src/utilities/buildable-libs-utils'; + import { NextBuildBuilderOptions } from '../../../utils/types'; -function getProjectDeps(context: BuilderContext, rootPackageJson: any) { +function getProjectDeps(context: ExecutorContext, rootPackageJson: any) { const projGraph = createProjectGraph(); const { dependencies: deps } = calculateProjectDependencies( projGraph, - context + context.root, + context.projectName, + context.targetName, + context.configurationName ); const depNames = deps .map((d) => d.node) @@ -36,20 +42,18 @@ function getProjectDeps(context: BuilderContext, rootPackageJson: any) { }; } -export async function createPackageJson( +export function createPackageJson( options: NextBuildBuilderOptions, - context: BuilderContext + context: ExecutorContext ) { - const rootPackageJson = readJsonFile( - join(context.workspaceRoot, 'package.json') - ); + const rootPackageJson = readJsonFile(join(context.root, 'package.json')); const { dependencies, devDependencies } = getProjectDeps( context, rootPackageJson ); const outPackageJson = { - name: context.target.project, + name: context.projectName, version: '0.0.1', scripts: { start: 'next start', diff --git a/packages/next/src/builders/build/schema.json b/packages/next/src/executors/build/schema.json similarity index 98% rename from packages/next/src/builders/build/schema.json rename to packages/next/src/executors/build/schema.json index e958d3ae64..faa33c011c 100644 --- a/packages/next/src/builders/build/schema.json +++ b/packages/next/src/executors/build/schema.json @@ -1,5 +1,6 @@ { "$schema": "http://json-schema.org/schema", + "cli": "nx", "title": "Next Build", "description": "Build a Next.js app", "type": "object", diff --git a/packages/next/src/executors/export/compat.ts b/packages/next/src/executors/export/compat.ts new file mode 100644 index 0000000000..7bc5844762 --- /dev/null +++ b/packages/next/src/executors/export/compat.ts @@ -0,0 +1,5 @@ +import { convertNxExecutor } from '@nrwl/devkit'; + +import exportExecutor from './export.impl'; + +export default convertNxExecutor(exportExecutor); diff --git a/packages/next/src/executors/export/export.impl.ts b/packages/next/src/executors/export/export.impl.ts new file mode 100644 index 0000000000..392fec6e0c --- /dev/null +++ b/packages/next/src/executors/export/export.impl.ts @@ -0,0 +1,52 @@ +import { + ExecutorContext, + parseTargetString, + readTargetOptions, + runExecutor, +} from '@nrwl/devkit'; +import exportApp from 'next/dist/export'; +import { PHASE_EXPORT } from 'next/dist/next-server/lib/constants'; +import { resolve } from 'path'; +import { prepareConfig } from '../../utils/config'; +import { + NextBuildBuilderOptions, + NextExportBuilderOptions, +} from '../../utils/types'; + +try { + require('dotenv').config(); +} catch (e) {} + +export default async function exportExecutor( + options: NextExportBuilderOptions, + context: ExecutorContext +) { + const buildTarget = parseTargetString(options.buildTarget); + const build = await runExecutor(buildTarget, {}, context); + + for await (const result of build) { + if (!result.success) { + return result; + } + } + + const buildOptions = readTargetOptions( + buildTarget, + context + ); + const root = resolve(context.root, buildOptions.root); + const config = prepareConfig(PHASE_EXPORT, buildOptions, context); + + await exportApp( + root, + { + statusMessage: 'Exporting', + silent: options.silent, + threads: options.threads, + outdir: `${buildOptions.outputPath}/exported`, + } as any, + config + ); + + return { success: true }; +} diff --git a/packages/next/src/builders/export/schema.json b/packages/next/src/executors/export/schema.json similarity index 97% rename from packages/next/src/builders/export/schema.json rename to packages/next/src/executors/export/schema.json index ef1b578cc5..6a6a17659f 100644 --- a/packages/next/src/builders/export/schema.json +++ b/packages/next/src/executors/export/schema.json @@ -1,4 +1,5 @@ { + "cli": "nx", "title": "Next Export", "description": "Export a Next.js app. The exported application is located at dist/$outputPath/exported.", "type": "object", diff --git a/packages/next/src/executors/server/compat.ts b/packages/next/src/executors/server/compat.ts new file mode 100644 index 0000000000..c70f628f39 --- /dev/null +++ b/packages/next/src/executors/server/compat.ts @@ -0,0 +1,5 @@ +import { convertNxExecutor } from '@nrwl/devkit'; + +import serverExecutor from './server.impl'; + +export default convertNxExecutor(serverExecutor); diff --git a/packages/next/src/builders/server/lib/custom-server.ts b/packages/next/src/executors/server/lib/custom-server.ts similarity index 100% rename from packages/next/src/builders/server/lib/custom-server.ts rename to packages/next/src/executors/server/lib/custom-server.ts diff --git a/packages/next/src/builders/server/lib/default-server.ts b/packages/next/src/executors/server/lib/default-server.ts similarity index 100% rename from packages/next/src/builders/server/lib/default-server.ts rename to packages/next/src/executors/server/lib/default-server.ts diff --git a/packages/next/src/builders/server/schema.json b/packages/next/src/executors/server/schema.json similarity index 98% rename from packages/next/src/builders/server/schema.json rename to packages/next/src/executors/server/schema.json index 0631c3df50..a5e627818e 100644 --- a/packages/next/src/builders/server/schema.json +++ b/packages/next/src/executors/server/schema.json @@ -1,4 +1,5 @@ { + "cli": "nx", "title": "Next Serve", "description": "Serve a Next.js app", "type": "object", diff --git a/packages/next/src/executors/server/server.impl.ts b/packages/next/src/executors/server/server.impl.ts new file mode 100644 index 0000000000..33fad4358a --- /dev/null +++ b/packages/next/src/executors/server/server.impl.ts @@ -0,0 +1,98 @@ +import { + ExecutorContext, + logger, + parseTargetString, + readTargetOptions, +} from '@nrwl/devkit'; +import { + PHASE_DEVELOPMENT_SERVER, + PHASE_PRODUCTION_SERVER, +} from 'next/dist/next-server/lib/constants'; + +import * as chalk from 'chalk'; +import { existsSync } from 'fs'; +import { join, resolve } from 'path'; + +import { prepareConfig } from '../../utils/config'; +import { + NextBuildBuilderOptions, + NextServeBuilderOptions, + NextServer, + NextServerOptions, + ProxyConfig, +} from '../../utils/types'; +import { customServer } from './lib/custom-server'; +import { defaultServer } from './lib/default-server'; + +try { + require('dotenv').config(); +} catch (e) {} + +const infoPrefix = `[ ${chalk.dim(chalk.cyan('info'))} ] `; +const readyPrefix = `[ ${chalk.green('ready')} ]`; + +export default async function* serveExecutor( + options: NextServeBuilderOptions, + context: ExecutorContext +) { + const buildTarget = parseTargetString(options.buildTarget); + const baseUrl = `http://${options.hostname || 'localhost'}:${options.port}`; + const buildOptions = readTargetOptions( + buildTarget, + context + ); + const root = resolve(context.root, buildOptions.root); + const config = prepareConfig( + options.dev ? PHASE_DEVELOPMENT_SERVER : PHASE_PRODUCTION_SERVER, + buildOptions, + context + ); + const settings: NextServerOptions = { + dev: options.dev, + dir: root, + staticMarkup: options.staticMarkup, + quiet: options.quiet, + conf: config, + port: options.port, + path: options.customServerPath, + hostname: options.hostname, + }; + + const server: NextServer = options.customServerPath + ? customServer + : defaultServer; + + // look for the proxy.conf.json + let proxyConfig: ProxyConfig; + const proxyConfigPath = options.proxyConfig + ? join(context.root, options.proxyConfig) + : join(root, 'proxy.conf.json'); + + if (existsSync(proxyConfigPath)) { + logger.info( + `${infoPrefix} found proxy configuration at ${proxyConfigPath}` + ); + proxyConfig = require(proxyConfigPath); + } + + try { + await server(settings, proxyConfig); + logger.info(`${readyPrefix} on ${baseUrl}`); + + yield { + baseUrl, + success: true, + }; + + // This Promise intentionally never resolves, leaving the process running + await new Promise<{ success: boolean }>(() => {}); + } catch (e) { + if (options.dev) { + throw e; + } else { + throw new Error( + `Could not start production server. Try building your app with \`nx build ${context.projectName}\`.` + ); + } + } +} diff --git a/packages/next/src/utils/config.spec.ts b/packages/next/src/utils/config.spec.ts index 1d14f98fb1..d84071a240 100644 --- a/packages/next/src/utils/config.spec.ts +++ b/packages/next/src/utils/config.spec.ts @@ -1,6 +1,7 @@ import { PHASE_PRODUCTION_BUILD } from 'next/dist/next-server/lib/constants'; import { TsconfigPathsPlugin } from 'tsconfig-paths-webpack-plugin'; import { createWebpackConfig, prepareConfig } from './config'; +import { NextBuildBuilderOptions } from '@nrwl/next'; jest.mock('tsconfig-paths-webpack-plugin'); jest.mock('next/dist/next-server/server/config', () => ({ @@ -93,7 +94,7 @@ describe('Next.js webpack config builder', () => { fileReplacements: [], nextConfig: require.resolve('./config.fixture'), customValue: 'test', - }, + } as NextBuildBuilderOptions, { workspaceRoot: '/root' } as any ); diff --git a/packages/next/src/utils/config.ts b/packages/next/src/utils/config.ts index 679dd8f33f..acdef5d098 100644 --- a/packages/next/src/utils/config.ts +++ b/packages/next/src/utils/config.ts @@ -1,3 +1,4 @@ +import { ExecutorContext, offsetFromRoot } from '@nrwl/devkit'; import { PHASE_DEVELOPMENT_SERVER, PHASE_EXPORT, @@ -9,8 +10,6 @@ import { join, resolve } from 'path'; import { TsconfigPathsPlugin } from 'tsconfig-paths-webpack-plugin'; import { Configuration } from 'webpack'; import { FileReplacement, NextBuildBuilderOptions } from './types'; -import { BuilderContext } from '@angular-devkit/architect'; -import { offsetFromRoot } from '@nrwl/devkit'; import { normalizeAssets } from '@nrwl/web/src/utils/normalize'; import { createCopyPlugin } from '@nrwl/web/src/utils/config'; @@ -122,7 +121,7 @@ export function prepareConfig( | typeof PHASE_DEVELOPMENT_SERVER | typeof PHASE_PRODUCTION_SERVER, options: NextBuildBuilderOptions, - context: BuilderContext + context: ExecutorContext ) { const config = loadConfig(phase, options.root, null); const userWebpack = config.webpack; @@ -134,7 +133,7 @@ export function prepareConfig( config.distDir = join(config.outdir, '.next'); config.webpack = (a, b) => createWebpackConfig( - context.workspaceRoot, + context.root, options.root, options.fileReplacements, options.assets diff --git a/packages/next/src/utils/testing.ts b/packages/next/src/utils/testing.ts deleted file mode 100644 index 2700675661..0000000000 --- a/packages/next/src/utils/testing.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Architect } from '@angular-devkit/architect'; -import { TestingArchitectHost } from '@angular-devkit/architect/testing'; -import { schema } from '@angular-devkit/core'; -import { MockBuilderContext } from '@nrwl/workspace/testing'; -import { join } from 'path'; - -export async function getTestArchitect() { - const architectHost = new TestingArchitectHost('/root', '/root'); - const registry = new schema.CoreSchemaRegistry(); - registry.addPostTransform(schema.transforms.addUndefinedDefaults); - - const architect = new Architect(architectHost, registry); - - await architectHost.addBuilderFromPackage(join(__dirname, '../..')); - - return [architect, architectHost] as [Architect, TestingArchitectHost]; -} - -export async function getMockContext() { - const [architect, architectHost] = await getTestArchitect(); - - const context = new MockBuilderContext(architect, architectHost); - await context.addBuilderFromPackage(join(__dirname, '../..')); - return context; -} diff --git a/packages/next/src/utils/types.ts b/packages/next/src/utils/types.ts index 9bcdcdbf85..a4e1110320 100644 --- a/packages/next/src/utils/types.ts +++ b/packages/next/src/utils/types.ts @@ -1,5 +1,3 @@ -import { JsonObject } from '@angular-devkit/core'; - export type NextServer = ( options: NextServerOptions, proxyConfig?: ProxyConfig @@ -25,12 +23,12 @@ export interface NextServerOptions { hostname: string; } -export interface FileReplacement extends JsonObject { +export interface FileReplacement { replace: string; with: string; } -export interface NextBuildBuilderOptions extends JsonObject { +export interface NextBuildBuilderOptions { root: string; outputPath: string; fileReplacements: FileReplacement[]; @@ -38,7 +36,7 @@ export interface NextBuildBuilderOptions extends JsonObject { nextConfig?: string; } -export interface NextServeBuilderOptions extends JsonObject { +export interface NextServeBuilderOptions { dev: boolean; port: number; staticMarkup: boolean; @@ -49,7 +47,7 @@ export interface NextServeBuilderOptions extends JsonObject { proxyConfig?: string; } -export interface NextExportBuilderOptions extends JsonObject { +export interface NextExportBuilderOptions { buildTarget: string; silent: boolean; threads: number;