feat(react): migrate next builders to devkit (#4861)
This commit is contained in:
parent
956dfe6509
commit
fd18b5edec
@ -68,6 +68,8 @@ describe('create-nx-workspace', () => {
|
|||||||
style: 'css',
|
style: 'css',
|
||||||
appName,
|
appName,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
expectNoAngularDevkit();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to create an web-components workspace', () => {
|
it('should be able to create an web-components workspace', () => {
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
"excludedFiles": ["./src/migrations/**"],
|
"excludedFiles": ["./src/migrations/**"],
|
||||||
"rules": {
|
"rules": {
|
||||||
"no-restricted-imports": [
|
"no-restricted-imports": [
|
||||||
"warn",
|
"error",
|
||||||
"@nrwl/workspace",
|
"@nrwl/workspace",
|
||||||
"@angular-devkit/core",
|
"@angular-devkit/core",
|
||||||
"@angular-devkit/schematics",
|
"@angular-devkit/schematics",
|
||||||
|
|||||||
@ -1,19 +1,35 @@
|
|||||||
{
|
{
|
||||||
"$schema": "@angular-devkit/architect/src/builders-schema.json",
|
"executors": {
|
||||||
"builders": {
|
|
||||||
"build": {
|
"build": {
|
||||||
"implementation": "./src/builders/build/build.impl",
|
"implementation": "./src/executors/build/build.impl",
|
||||||
"schema": "./src/builders/build/schema.json",
|
"schema": "./src/executors/build/schema.json",
|
||||||
"description": "Build a Next.js app"
|
"description": "Build a Next.js app"
|
||||||
},
|
},
|
||||||
"server": {
|
"server": {
|
||||||
"implementation": "./src/builders/server/server.impl",
|
"implementation": "./src/executors/server/server.impl",
|
||||||
"schema": "./src/builders/server/schema.json",
|
"schema": "./src/executors/server/schema.json",
|
||||||
"description": "Serve a Next.js app"
|
"description": "Serve a Next.js app"
|
||||||
},
|
},
|
||||||
"export": {
|
"export": {
|
||||||
"implementation": "./src/builders/export/export.impl",
|
"implementation": "./src/executors/export/export.impl",
|
||||||
"schema": "./src/builders/export/schema.json",
|
"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."
|
"description": "Export a Next.js app. The exported application is located at dist/$outputPath/exported."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,9 +37,7 @@
|
|||||||
"@nrwl/jest": "*",
|
"@nrwl/jest": "*",
|
||||||
"@nrwl/linter": "*",
|
"@nrwl/linter": "*",
|
||||||
"@nrwl/web": "*",
|
"@nrwl/web": "*",
|
||||||
"@angular-devkit/architect": "~0.1102.0",
|
"@nrwl/workspace": "*",
|
||||||
"@angular-devkit/schematics": "~11.2.0",
|
|
||||||
"@angular-devkit/core": "~11.2.0",
|
|
||||||
"@svgr/webpack": "^5.4.0",
|
"@svgr/webpack": "^5.4.0",
|
||||||
"chalk": "4.1.0",
|
"chalk": "4.1.0",
|
||||||
"copy-webpack-plugin": "6.0.3",
|
"copy-webpack-plugin": "6.0.3",
|
||||||
|
|||||||
@ -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<NextBuildBuilderOptions>(run);
|
|
||||||
|
|
||||||
export function run(
|
|
||||||
options: NextBuildBuilderOptions,
|
|
||||||
context: BuilderContext
|
|
||||||
): Observable<BuilderOutput> {
|
|
||||||
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 }))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -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<NextExportBuilderOptions>(run);
|
|
||||||
|
|
||||||
function run(
|
|
||||||
options: NextExportBuilderOptions,
|
|
||||||
context: BuilderContext
|
|
||||||
): Observable<BuilderOutput> {
|
|
||||||
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 })));
|
|
||||||
})
|
|
||||||
);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -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<NextServeBuilderOptions>(run);
|
|
||||||
|
|
||||||
const infoPrefix = `[ ${chalk.dim(chalk.cyan('info'))} ] `;
|
|
||||||
const readyPrefix = `[ ${chalk.green('ready')} ]`;
|
|
||||||
|
|
||||||
export function run(
|
|
||||||
options: NextServeBuilderOptions,
|
|
||||||
context: BuilderContext
|
|
||||||
): Observable<BuilderOutput> {
|
|
||||||
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<BuilderOutput>((obs) => {
|
|
||||||
obs.next({
|
|
||||||
baseUrl,
|
|
||||||
success: true,
|
|
||||||
});
|
|
||||||
})
|
|
||||||
)
|
|
||||||
);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,8 +1,9 @@
|
|||||||
import { MockBuilderContext } from '@nrwl/workspace/testing';
|
import { ExecutorContext } from '@nrwl/devkit';
|
||||||
|
|
||||||
import * as build from 'next/dist/build';
|
import * as build from 'next/dist/build';
|
||||||
import { getMockContext } from '../../utils/testing';
|
|
||||||
import { NextBuildBuilderOptions } from '../../utils/types';
|
import { NextBuildBuilderOptions } from '../../utils/types';
|
||||||
import { run } from './build.impl';
|
import buildExecutor from './build.impl';
|
||||||
|
|
||||||
jest.mock('fs-extra');
|
jest.mock('fs-extra');
|
||||||
jest.mock('next/dist/build');
|
jest.mock('next/dist/build');
|
||||||
@ -13,12 +14,21 @@ jest.mock('./lib/create-package-json', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('Next.js Builder', () => {
|
describe('Next.js Builder', () => {
|
||||||
let context: MockBuilderContext;
|
let context: ExecutorContext;
|
||||||
let options: NextBuildBuilderOptions;
|
let options: NextBuildBuilderOptions;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
context = await getMockContext();
|
context = {
|
||||||
|
root: '/root',
|
||||||
|
cwd: '/root',
|
||||||
|
projectName: 'my-app',
|
||||||
|
targetName: 'build',
|
||||||
|
workspace: {
|
||||||
|
version: 2,
|
||||||
|
projects: {},
|
||||||
|
},
|
||||||
|
isVerbose: false,
|
||||||
|
};
|
||||||
options = {
|
options = {
|
||||||
root: 'apps/wibble',
|
root: 'apps/wibble',
|
||||||
outputPath: 'dist/apps/wibble',
|
outputPath: 'dist/apps/wibble',
|
||||||
@ -34,7 +44,7 @@ describe('Next.js Builder', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should call next build', async () => {
|
it('should call next build', async () => {
|
||||||
await run(options, context).toPromise();
|
await buildExecutor(options, context);
|
||||||
|
|
||||||
expect(build.default).toHaveBeenCalledWith(
|
expect(build.default).toHaveBeenCalledWith(
|
||||||
'/root/apps/wibble',
|
'/root/apps/wibble',
|
||||||
31
packages/next/src/executors/build/build.impl.ts
Normal file
31
packages/next/src/executors/build/build.impl.ts
Normal file
@ -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 };
|
||||||
|
}
|
||||||
5
packages/next/src/executors/build/compat.ts
Normal file
5
packages/next/src/executors/build/compat.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { convertNxExecutor } from '@nrwl/devkit';
|
||||||
|
|
||||||
|
import buildExecutor from './build.impl';
|
||||||
|
|
||||||
|
export default convertNxExecutor(buildExecutor);
|
||||||
@ -1,15 +1,17 @@
|
|||||||
|
import { ExecutorContext } from '@nrwl/devkit';
|
||||||
|
|
||||||
import { copyFileSync, existsSync } from 'fs';
|
import { copyFileSync, existsSync } from 'fs';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { BuilderContext } from '@angular-devkit/architect';
|
|
||||||
import { NextBuildBuilderOptions } from '../../../utils/types';
|
import { NextBuildBuilderOptions } from '../../../utils/types';
|
||||||
|
|
||||||
export async function createNextConfigFile(
|
export function createNextConfigFile(
|
||||||
options: NextBuildBuilderOptions,
|
options: NextBuildBuilderOptions,
|
||||||
context: BuilderContext
|
context: ExecutorContext
|
||||||
) {
|
) {
|
||||||
const nextConfigPath = options.nextConfig
|
const nextConfigPath = options.nextConfig
|
||||||
? join(context.workspaceRoot, options.nextConfig)
|
? join(context.root, options.nextConfig)
|
||||||
: join(context.workspaceRoot, options.root, 'next.config.js');
|
: join(context.root, options.root, 'next.config.js');
|
||||||
|
|
||||||
if (existsSync(nextConfigPath)) {
|
if (existsSync(nextConfigPath)) {
|
||||||
copyFileSync(nextConfigPath, join(options.outputPath, 'next.config.js'));
|
copyFileSync(nextConfigPath, join(options.outputPath, 'next.config.js'));
|
||||||
@ -1,16 +1,22 @@
|
|||||||
import { BuilderContext } from '@angular-devkit/architect';
|
import { ExecutorContext } from '@nrwl/devkit';
|
||||||
|
|
||||||
import { writeFileSync } from 'fs';
|
import { writeFileSync } from 'fs';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { readJsonFile } from '@nrwl/workspace';
|
|
||||||
import { createProjectGraph } from '@nrwl/workspace/src/core/project-graph';
|
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';
|
import { NextBuildBuilderOptions } from '../../../utils/types';
|
||||||
|
|
||||||
function getProjectDeps(context: BuilderContext, rootPackageJson: any) {
|
function getProjectDeps(context: ExecutorContext, rootPackageJson: any) {
|
||||||
const projGraph = createProjectGraph();
|
const projGraph = createProjectGraph();
|
||||||
const { dependencies: deps } = calculateProjectDependencies(
|
const { dependencies: deps } = calculateProjectDependencies(
|
||||||
projGraph,
|
projGraph,
|
||||||
context
|
context.root,
|
||||||
|
context.projectName,
|
||||||
|
context.targetName,
|
||||||
|
context.configurationName
|
||||||
);
|
);
|
||||||
const depNames = deps
|
const depNames = deps
|
||||||
.map((d) => d.node)
|
.map((d) => d.node)
|
||||||
@ -36,20 +42,18 @@ function getProjectDeps(context: BuilderContext, rootPackageJson: any) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createPackageJson(
|
export function createPackageJson(
|
||||||
options: NextBuildBuilderOptions,
|
options: NextBuildBuilderOptions,
|
||||||
context: BuilderContext
|
context: ExecutorContext
|
||||||
) {
|
) {
|
||||||
const rootPackageJson = readJsonFile(
|
const rootPackageJson = readJsonFile(join(context.root, 'package.json'));
|
||||||
join(context.workspaceRoot, 'package.json')
|
|
||||||
);
|
|
||||||
const { dependencies, devDependencies } = getProjectDeps(
|
const { dependencies, devDependencies } = getProjectDeps(
|
||||||
context,
|
context,
|
||||||
rootPackageJson
|
rootPackageJson
|
||||||
);
|
);
|
||||||
|
|
||||||
const outPackageJson = {
|
const outPackageJson = {
|
||||||
name: context.target.project,
|
name: context.projectName,
|
||||||
version: '0.0.1',
|
version: '0.0.1',
|
||||||
scripts: {
|
scripts: {
|
||||||
start: 'next start',
|
start: 'next start',
|
||||||
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/schema",
|
"$schema": "http://json-schema.org/schema",
|
||||||
|
"cli": "nx",
|
||||||
"title": "Next Build",
|
"title": "Next Build",
|
||||||
"description": "Build a Next.js app",
|
"description": "Build a Next.js app",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
5
packages/next/src/executors/export/compat.ts
Normal file
5
packages/next/src/executors/export/compat.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { convertNxExecutor } from '@nrwl/devkit';
|
||||||
|
|
||||||
|
import exportExecutor from './export.impl';
|
||||||
|
|
||||||
|
export default convertNxExecutor(exportExecutor);
|
||||||
52
packages/next/src/executors/export/export.impl.ts
Normal file
52
packages/next/src/executors/export/export.impl.ts
Normal file
@ -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<NextBuildBuilderOptions>(
|
||||||
|
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 };
|
||||||
|
}
|
||||||
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"cli": "nx",
|
||||||
"title": "Next Export",
|
"title": "Next Export",
|
||||||
"description": "Export a Next.js app. The exported application is located at dist/$outputPath/exported.",
|
"description": "Export a Next.js app. The exported application is located at dist/$outputPath/exported.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
5
packages/next/src/executors/server/compat.ts
Normal file
5
packages/next/src/executors/server/compat.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { convertNxExecutor } from '@nrwl/devkit';
|
||||||
|
|
||||||
|
import serverExecutor from './server.impl';
|
||||||
|
|
||||||
|
export default convertNxExecutor(serverExecutor);
|
||||||
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"cli": "nx",
|
||||||
"title": "Next Serve",
|
"title": "Next Serve",
|
||||||
"description": "Serve a Next.js app",
|
"description": "Serve a Next.js app",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
98
packages/next/src/executors/server/server.impl.ts
Normal file
98
packages/next/src/executors/server/server.impl.ts
Normal file
@ -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<NextBuildBuilderOptions>(
|
||||||
|
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}\`.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
import { PHASE_PRODUCTION_BUILD } from 'next/dist/next-server/lib/constants';
|
import { PHASE_PRODUCTION_BUILD } from 'next/dist/next-server/lib/constants';
|
||||||
import { TsconfigPathsPlugin } from 'tsconfig-paths-webpack-plugin';
|
import { TsconfigPathsPlugin } from 'tsconfig-paths-webpack-plugin';
|
||||||
import { createWebpackConfig, prepareConfig } from './config';
|
import { createWebpackConfig, prepareConfig } from './config';
|
||||||
|
import { NextBuildBuilderOptions } from '@nrwl/next';
|
||||||
|
|
||||||
jest.mock('tsconfig-paths-webpack-plugin');
|
jest.mock('tsconfig-paths-webpack-plugin');
|
||||||
jest.mock('next/dist/next-server/server/config', () => ({
|
jest.mock('next/dist/next-server/server/config', () => ({
|
||||||
@ -93,7 +94,7 @@ describe('Next.js webpack config builder', () => {
|
|||||||
fileReplacements: [],
|
fileReplacements: [],
|
||||||
nextConfig: require.resolve('./config.fixture'),
|
nextConfig: require.resolve('./config.fixture'),
|
||||||
customValue: 'test',
|
customValue: 'test',
|
||||||
},
|
} as NextBuildBuilderOptions,
|
||||||
{ workspaceRoot: '/root' } as any
|
{ workspaceRoot: '/root' } as any
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { ExecutorContext, offsetFromRoot } from '@nrwl/devkit';
|
||||||
import {
|
import {
|
||||||
PHASE_DEVELOPMENT_SERVER,
|
PHASE_DEVELOPMENT_SERVER,
|
||||||
PHASE_EXPORT,
|
PHASE_EXPORT,
|
||||||
@ -9,8 +10,6 @@ import { join, resolve } from 'path';
|
|||||||
import { TsconfigPathsPlugin } from 'tsconfig-paths-webpack-plugin';
|
import { TsconfigPathsPlugin } from 'tsconfig-paths-webpack-plugin';
|
||||||
import { Configuration } from 'webpack';
|
import { Configuration } from 'webpack';
|
||||||
import { FileReplacement, NextBuildBuilderOptions } from './types';
|
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 { normalizeAssets } from '@nrwl/web/src/utils/normalize';
|
||||||
import { createCopyPlugin } from '@nrwl/web/src/utils/config';
|
import { createCopyPlugin } from '@nrwl/web/src/utils/config';
|
||||||
|
|
||||||
@ -122,7 +121,7 @@ export function prepareConfig(
|
|||||||
| typeof PHASE_DEVELOPMENT_SERVER
|
| typeof PHASE_DEVELOPMENT_SERVER
|
||||||
| typeof PHASE_PRODUCTION_SERVER,
|
| typeof PHASE_PRODUCTION_SERVER,
|
||||||
options: NextBuildBuilderOptions,
|
options: NextBuildBuilderOptions,
|
||||||
context: BuilderContext
|
context: ExecutorContext
|
||||||
) {
|
) {
|
||||||
const config = loadConfig(phase, options.root, null);
|
const config = loadConfig(phase, options.root, null);
|
||||||
const userWebpack = config.webpack;
|
const userWebpack = config.webpack;
|
||||||
@ -134,7 +133,7 @@ export function prepareConfig(
|
|||||||
config.distDir = join(config.outdir, '.next');
|
config.distDir = join(config.outdir, '.next');
|
||||||
config.webpack = (a, b) =>
|
config.webpack = (a, b) =>
|
||||||
createWebpackConfig(
|
createWebpackConfig(
|
||||||
context.workspaceRoot,
|
context.root,
|
||||||
options.root,
|
options.root,
|
||||||
options.fileReplacements,
|
options.fileReplacements,
|
||||||
options.assets
|
options.assets
|
||||||
|
|||||||
@ -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;
|
|
||||||
}
|
|
||||||
@ -1,5 +1,3 @@
|
|||||||
import { JsonObject } from '@angular-devkit/core';
|
|
||||||
|
|
||||||
export type NextServer = (
|
export type NextServer = (
|
||||||
options: NextServerOptions,
|
options: NextServerOptions,
|
||||||
proxyConfig?: ProxyConfig
|
proxyConfig?: ProxyConfig
|
||||||
@ -25,12 +23,12 @@ export interface NextServerOptions {
|
|||||||
hostname: string;
|
hostname: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FileReplacement extends JsonObject {
|
export interface FileReplacement {
|
||||||
replace: string;
|
replace: string;
|
||||||
with: string;
|
with: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NextBuildBuilderOptions extends JsonObject {
|
export interface NextBuildBuilderOptions {
|
||||||
root: string;
|
root: string;
|
||||||
outputPath: string;
|
outputPath: string;
|
||||||
fileReplacements: FileReplacement[];
|
fileReplacements: FileReplacement[];
|
||||||
@ -38,7 +36,7 @@ export interface NextBuildBuilderOptions extends JsonObject {
|
|||||||
nextConfig?: string;
|
nextConfig?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NextServeBuilderOptions extends JsonObject {
|
export interface NextServeBuilderOptions {
|
||||||
dev: boolean;
|
dev: boolean;
|
||||||
port: number;
|
port: number;
|
||||||
staticMarkup: boolean;
|
staticMarkup: boolean;
|
||||||
@ -49,7 +47,7 @@ export interface NextServeBuilderOptions extends JsonObject {
|
|||||||
proxyConfig?: string;
|
proxyConfig?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NextExportBuilderOptions extends JsonObject {
|
export interface NextExportBuilderOptions {
|
||||||
buildTarget: string;
|
buildTarget: string;
|
||||||
silent: boolean;
|
silent: boolean;
|
||||||
threads: number;
|
threads: number;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user