diff --git a/e2e/plugins-nx-cloudflare-e2e/tests/next-on-pages.spec.ts b/e2e/plugins-nx-cloudflare-e2e/tests/next-on-pages.spec.ts new file mode 100644 index 000000000..60aa3c0f8 --- /dev/null +++ b/e2e/plugins-nx-cloudflare-e2e/tests/next-on-pages.spec.ts @@ -0,0 +1,36 @@ +import { + uniq, + runNxCommand, + ensureNxProject, + cleanup, + readJson, + updateFile, +} from '@nx/plugin/testing'; + +const workerapp = uniq('workerapp'); + +describe('Next on Pages', () => { + beforeEach(() => { + ensureNxProject( + '@naxodev/nx-cloudflare', + 'dist/packages/plugins/nx-cloudflare' + ); + + runNxCommand( + `generate @nx/next:app --name ${workerapp} --directory="apps" --appDir` + ); + }); + + afterEach(() => cleanup()); + + it('should build a NextJS application with the next-on-pages script', async () => { + const projectJson = readJson(`apps/${workerapp}/project.json`); + projectJson.targets.build.executor = '@naxodev/nx-cloudflare:next-build'; + updateFile(`apps/${workerapp}/project.json`, JSON.stringify(projectJson)); + + const buildResults = runNxCommand(`build ${workerapp}`); + expect(buildResults).toContain( + `NX Successfully ran target build for project ${workerapp}` + ); + }, 120_000); +}); diff --git a/packages/plugins/nx-cloudflare/package.json b/packages/plugins/nx-cloudflare/package.json index 02189e804..9274f0e25 100644 --- a/packages/plugins/nx-cloudflare/package.json +++ b/packages/plugins/nx-cloudflare/package.json @@ -41,8 +41,7 @@ "webpack": "^5.88.2", "nx": "^17.0.0", "@nx/workspace": "^17.0.0", - "@nx/web": "^17.0.0", - "@cloudflare/next-on-pages": "^1.6.3" + "@nx/web": "^17.0.0" }, "dependencies": { "@nx/devkit": "^17.0.0", diff --git a/packages/plugins/nx-cloudflare/src/executors/next-build/build.impl.ts b/packages/plugins/nx-cloudflare/src/executors/next-build/build.impl.ts index aa1513e84..940cd72d2 100644 --- a/packages/plugins/nx-cloudflare/src/executors/next-build/build.impl.ts +++ b/packages/plugins/nx-cloudflare/src/executors/next-build/build.impl.ts @@ -3,14 +3,20 @@ import 'dotenv/config'; import { detectPackageManager, ExecutorContext, + getPackageManagerCommand, logger, readJsonFile, - workspaceRoot, writeJsonFile, } from '@nx/devkit'; import { createLockFile, createPackageJson, getLockFileName } from '@nx/js'; -import { join, resolve as pathResolve } from 'path'; -import { copySync, existsSync, mkdir, writeFileSync } from 'fs-extra'; +import { join } from 'path'; +import { + copySync, + ensureDirSync, + existsSync, + mkdir, + writeFileSync, +} from 'fs-extra'; import { gte } from 'semver'; import { directoryExists } from '@nx/workspace/src/utilities/fileutils'; import { checkAndCleanWithSemver } from '@nx/devkit/src/utils/semver'; @@ -19,15 +25,15 @@ import { updatePackageJson } from './lib/update-package-json'; import { createNextConfigFile } from './lib/create-next-config-file'; import { checkPublicDirectory } from './lib/check-project'; import { NextBuildBuilderOptions } from '../../utils/types'; -import { ChildProcess, fork } from 'child_process'; +import { execSync, ExecSyncOptions } from 'child_process'; import { createCliOptions } from '../../utils/create-cli-options'; -let childProcess: ChildProcess; - // This executor is a modified version of the original `@nrwl/next:build` executor. // It's main modification is to use the cloudflare next-on-pages package. // Because the Cloudflare builder doesn't allow us to locate the build output outside the project root directory // we need to change the output path config options to the project root directory and then copy the build output to the desired output path. +// We also move from invoking the bin script to executing the command with the `execSync` function. This is because the bin script +// is not exported on the package.json export default async function buildExecutor( options: NextBuildBuilderOptions, context: ExecutorContext @@ -54,21 +60,18 @@ export default async function buildExecutor( if (hasReact18) { process.env['__NEXT_REACT_ROOT'] ||= 'true'; } + ensureDirSync(join(projectRoot, '.vercel')); const { outputPath: originalOutputPath } = options; // Set the outputPath to the projectRoot to bypass cloudflare builded limitations. options.outputPath = projectRoot; try { - await runCliBuild(workspaceRoot, projectRoot, options); + runCliBuild(projectRoot, options); } catch (error) { logger.error(`Error occurred while trying to run the build command`); logger.error(error); return { success: false }; - } finally { - if (childProcess) { - childProcess.kill(); - } } if (!directoryExists(options.outputPath)) { @@ -130,11 +133,7 @@ export default async function buildExecutor( return { success: true }; } -function runCliBuild( - workspaceRoot: string, - projectRoot: string, - options: NextBuildBuilderOptions -) { +function runCliBuild(projectRoot: string, options: NextBuildBuilderOptions) { const { experimentalAppOnly, profile, debug, outputPath } = options; // Set output path here since it can also be set via CLI @@ -142,31 +141,16 @@ function runCliBuild( process.env.NX_NEXT_OUTPUT_PATH ??= outputPath; const args = createCliOptions({ experimentalAppOnly, profile, debug }); - return new Promise((resolve, reject) => { - childProcess = fork( - require.resolve('@cloudflare/next-on-pages/bin'), - [...args], - { - cwd: pathResolve(workspaceRoot, projectRoot), - stdio: 'inherit', - env: process.env, - } - ); - // Ensure the child process is killed when the parent exits - process.on('exit', () => childProcess.kill()); - process.on('SIGTERM', () => childProcess.kill()); - - childProcess.on('error', (err) => { - reject(err); - }); + const pmc = getPackageManagerCommand('npm'); + const execSyncOptions: ExecSyncOptions = { + stdio: ['inherit', 'inherit', 'inherit'], + encoding: 'utf-8', + cwd: projectRoot, + }; - childProcess.on('exit', (code) => { - if (code === 0) { - resolve(code); - } else { - reject(code); - } - }); - }); + execSync( + `${pmc.exec} @cloudflare/next-on-pages ${args.join(' ')}`, + execSyncOptions + ); } diff --git a/tools/scripts/start-local-registry.ts b/tools/scripts/start-local-registry.ts index 112f8606b..e84c6c78e 100644 --- a/tools/scripts/start-local-registry.ts +++ b/tools/scripts/start-local-registry.ts @@ -19,7 +19,7 @@ export default async () => { const nx = require.resolve('nx'); execFileSync( nx, - ['run-many', '--targets', 'publish', '--ver', '999.0.0', '--tag', 'e2e'], + ['run-many', '--targets', 'publish', '--ver', '0.0.0-e2e', '--tag', 'e2e'], { env: process.env, stdio: 'inherit' } ); };