Skip to content

Commit 7eabc1f

Browse files
fix(next): derive workflow project root (#2729)
* fix(next): derive workflow project root * test(next): clean temp root after leaving app dir * chore(next): simplify project root detection * chore(next): mirror root detection
1 parent 5b7fa7c commit 7eabc1f

2 files changed

Lines changed: 80 additions & 6 deletions

File tree

‎.changeset/next-root-detection.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@workflow/next": patch
3+
---
4+
5+
Derive the workflow builder project root from Next.js workspace root configuration.

‎packages/next/src/index.ts‎

Lines changed: 75 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { copyFileSync, mkdirSync, statSync } from 'node:fs';
22
import { copyFile, mkdir, readFile } from 'node:fs/promises';
3-
import { dirname, isAbsolute, join } from 'node:path';
3+
import { dirname, isAbsolute, join, resolve } from 'node:path';
44
import type { NextConfig } from 'next';
55
import semver from 'semver';
66
import { getNextBuilder } from './builder.js';
@@ -16,7 +16,6 @@ const VERCEL_WORLD_SERVER_EXTERNAL_PACKAGES = [
1616
VERCEL_WORLD_PACKAGE,
1717
...VERCEL_WORLD_DEPENDENCY_PACKAGES,
1818
];
19-
2019
const useWorkflowPattern = /^\s*(['"])use workflow\1;?\s*$/m;
2120
const useStepPattern = /^\s*(['"])use step\1;?\s*$/m;
2221
const workflowSerdeImportPattern = /from\s+(['"])@workflow\/serde\1/;
@@ -232,6 +231,74 @@ function fileExists(path: string): boolean {
232231
}
233232
}
234233

234+
function findRootFile(names: string[], workingDir: string): string | undefined {
235+
let current = resolve(workingDir);
236+
237+
while (true) {
238+
for (const name of names) {
239+
const file = join(current, name);
240+
if (fileExists(file)) {
241+
return file;
242+
}
243+
}
244+
245+
const parent = dirname(current);
246+
if (parent === current) {
247+
return undefined;
248+
}
249+
current = parent;
250+
}
251+
}
252+
253+
function findNextRootFile(workingDir: string): string | undefined {
254+
return (
255+
findRootFile(['pnpm-workspace.yaml'], workingDir) ??
256+
findRootFile(
257+
[
258+
'pnpm-lock.yaml',
259+
'package-lock.json',
260+
'yarn.lock',
261+
'bun.lock',
262+
'bun.lockb',
263+
],
264+
workingDir
265+
)
266+
);
267+
}
268+
269+
function resolveNextProjectRoot(
270+
nextConfig: NextConfig,
271+
workingDir: string
272+
): string {
273+
const configuredRoot =
274+
nextConfig.outputFileTracingRoot ?? nextConfig.turbopack?.root;
275+
276+
if (configuredRoot) {
277+
return isAbsolute(configuredRoot)
278+
? configuredRoot
279+
: resolve(workingDir, configuredRoot);
280+
}
281+
282+
let rootFile = findNextRootFile(workingDir);
283+
if (!rootFile) {
284+
return workingDir;
285+
}
286+
287+
while (true) {
288+
const currentDir = dirname(rootFile);
289+
const parentDir = dirname(currentDir);
290+
if (parentDir === currentDir) {
291+
return currentDir;
292+
}
293+
294+
const parentRootFile = findNextRootFile(parentDir);
295+
if (!parentRootFile) {
296+
return currentDir;
297+
}
298+
rootFile = parentRootFile;
299+
}
300+
}
301+
235302
function getWorkflowManifestCopyPaths({
236303
projectDir,
237304
distDir,
@@ -442,7 +509,9 @@ export function withWorkflow(
442509
nextConfig.turbopack.rules = {};
443510
}
444511
const existingRules = nextConfig.turbopack.rules as any;
445-
const nextVersion = resolveNextVersion(process.cwd());
512+
const workingDir = process.cwd();
513+
const nextVersion = resolveNextVersion(workingDir);
514+
const projectRoot = resolveNextProjectRoot(nextConfig, workingDir);
446515
const supportsTurboCondition = semver.gte(nextVersion, 'v16.0.0');
447516

448517
const shouldWatch = process.env.NODE_ENV === 'development';
@@ -474,9 +543,9 @@ export function withWorkflow(
474543
'jsx',
475544
'js',
476545
],
477-
projectRoot: nextConfig.outputFileTracingRoot,
478-
moduleSpecifierRoot: process.cwd(),
479-
workingDir: process.cwd(),
546+
projectRoot,
547+
moduleSpecifierRoot: workingDir,
548+
workingDir,
480549
distDir,
481550
diagnosticsDir: `${distDir}/diagnostics`,
482551
buildTarget: 'next',

0 commit comments

Comments
 (0)