Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/witty-mails-smile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@workflow/next": patch
---

Allow `WORKFLOW_NEXT_LAZY_DISCOVERY=0` to explicitly disable deferred Next.js discovery
2 changes: 1 addition & 1 deletion .github/scripts/generate-docs-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ function parseE2EResults(files) {
// Extract framework from filename for detailed breakdown
const basename = path.basename(file, '.json');
const frameworkMatch = basename.match(
/-(nextjs-turbopack|nextjs-webpack|nitro|nuxt|sveltekit|vite|hono|express|fastify|astro)(?:-(canary|stable))?$/
/-(nextjs-turbopack|nextjs-webpack|nitro|nuxt|sveltekit|vite|hono|express|fastify|astro)(?:-(?:canary|stable(?:-lazy-discovery-(?:enabled|disabled))?))?$/
);
if (frameworkMatch) {
const framework = frameworkMatch[1];
Expand Down
34 changes: 19 additions & 15 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ jobs:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
WORKFLOW_PUBLIC_MANIFEST: '1'
WORKFLOW_NEXT_LAZY_DISCOVERY: ${{ matrix.app.canary != true && (matrix.app.name == 'nextjs-turbopack' || matrix.app.name == 'nextjs-webpack') && '0' || '' }}
steps:
- name: Checkout Repo
uses: actions/checkout@v4
Expand Down Expand Up @@ -332,7 +333,7 @@ jobs:
run: echo "matrix=$(node ./scripts/create-test-matrix.mjs)" >> $GITHUB_OUTPUT

e2e-local-dev:
name: E2E Local Dev Tests (${{ matrix.app.name }} - ${{ matrix.app.canary && 'canary' || 'stable' }})
name: E2E Local Dev Tests (${{ matrix.app.name }} - ${{ matrix.app.runLabel }})
runs-on: ubuntu-latest
timeout-minutes: 30
if: ${{ !contains(github.event.pull_request.labels.*.name, 'workflow-server-test') }}
Expand All @@ -345,6 +346,7 @@ jobs:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
WORKFLOW_PUBLIC_MANIFEST: '1'
WORKFLOW_NEXT_LAZY_DISCOVERY: ${{ matrix.app.lazyDiscovery == false && '0' || matrix.app.lazyDiscovery == true && '1' || '' }}

steps:
- name: Checkout Repo
Expand Down Expand Up @@ -382,7 +384,7 @@ jobs:
cd "${{ steps.prepare-workbench.outputs.workbench_app_path }}" && pnpm dev &
echo "starting tests in 10 seconds" && sleep 10
pnpm vitest run packages/core/e2e/dev.test.ts; sleep 10
pnpm run test:e2e --reporter=default --reporter=json --reporter=./packages/core/e2e/github-reporter.ts --outputFile=e2e-local-dev-${{ matrix.app.name }}-${{ matrix.app.canary && 'canary' || 'stable' }}.json
pnpm run test:e2e --reporter=default --reporter=json --reporter=./packages/core/e2e/github-reporter.ts --outputFile=e2e-local-dev-${{ matrix.app.name }}-${{ matrix.app.artifactSuffix }}.json
env:
NODE_OPTIONS: "--enable-source-maps"
APP_NAME: ${{ matrix.app.name }}
Expand All @@ -393,19 +395,19 @@ jobs:

- name: Generate E2E summary
if: always()
run: node .github/scripts/aggregate-e2e-results.js . --job-name "E2E Local Dev (${{ matrix.app.name }})" >> $GITHUB_STEP_SUMMARY || true
run: node .github/scripts/aggregate-e2e-results.js . --job-name "E2E Local Dev (${{ matrix.app.name }} - ${{ matrix.app.runLabel }})" >> $GITHUB_STEP_SUMMARY || true

- name: Upload E2E results
if: always()
uses: actions/upload-artifact@v4
with:
name: e2e-results-local-dev-${{ matrix.app.name }}-${{ matrix.app.canary && 'canary' || 'stable' }}
path: e2e-local-dev-${{ matrix.app.name }}-${{ matrix.app.canary && 'canary' || 'stable' }}.json
name: e2e-results-local-dev-${{ matrix.app.name }}-${{ matrix.app.artifactSuffix }}
path: e2e-local-dev-${{ matrix.app.name }}-${{ matrix.app.artifactSuffix }}.json
retention-days: 7
if-no-files-found: ignore

e2e-local-prod:
name: E2E Local Prod Tests (${{ matrix.app.name }} - ${{ matrix.app.canary && 'canary' || 'stable' }})
name: E2E Local Prod Tests (${{ matrix.app.name }} - ${{ matrix.app.runLabel }})
runs-on: ubuntu-latest
timeout-minutes: 30
if: ${{ !contains(github.event.pull_request.labels.*.name, 'workflow-server-test') }}
Expand All @@ -418,6 +420,7 @@ jobs:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
WORKFLOW_PUBLIC_MANIFEST: '1'
WORKFLOW_NEXT_LAZY_DISCOVERY: ${{ matrix.app.lazyDiscovery == false && '0' || matrix.app.lazyDiscovery == true && '1' || '' }}

steps:
- name: Checkout Repo
Expand Down Expand Up @@ -460,7 +463,7 @@ jobs:
run: |
cd "${{ steps.prepare-workbench.outputs.workbench_app_path }}" && pnpm start &
echo "starting tests in 10 seconds" && sleep 10
pnpm run test:e2e --reporter=default --reporter=json --reporter=./packages/core/e2e/github-reporter.ts --outputFile=e2e-local-prod-${{ matrix.app.name }}-${{ matrix.app.canary && 'canary' || 'stable' }}.json
pnpm run test:e2e --reporter=default --reporter=json --reporter=./packages/core/e2e/github-reporter.ts --outputFile=e2e-local-prod-${{ matrix.app.name }}-${{ matrix.app.artifactSuffix }}.json
env:
NODE_OPTIONS: "--enable-source-maps"
APP_NAME: ${{ matrix.app.name }}
Expand All @@ -470,19 +473,19 @@ jobs:

- name: Generate E2E summary
if: always()
run: node .github/scripts/aggregate-e2e-results.js . --job-name "E2E Local Prod (${{ matrix.app.name }})" >> $GITHUB_STEP_SUMMARY || true
run: node .github/scripts/aggregate-e2e-results.js . --job-name "E2E Local Prod (${{ matrix.app.name }} - ${{ matrix.app.runLabel }})" >> $GITHUB_STEP_SUMMARY || true

- name: Upload E2E results
if: always()
uses: actions/upload-artifact@v4
with:
name: e2e-results-local-prod-${{ matrix.app.name }}-${{ matrix.app.canary && 'canary' || 'stable' }}
path: e2e-local-prod-${{ matrix.app.name }}-${{ matrix.app.canary && 'canary' || 'stable' }}.json
name: e2e-results-local-prod-${{ matrix.app.name }}-${{ matrix.app.artifactSuffix }}
path: e2e-local-prod-${{ matrix.app.name }}-${{ matrix.app.artifactSuffix }}.json
retention-days: 7
if-no-files-found: ignore

e2e-local-postgres:
name: E2E Local Postgres Tests (${{ matrix.app.name }} - ${{ matrix.app.canary && 'canary' || 'stable' }})
name: E2E Local Postgres Tests (${{ matrix.app.name }} - ${{ matrix.app.runLabel }})
runs-on: ubuntu-latest
timeout-minutes: 30
if: ${{ !contains(github.event.pull_request.labels.*.name, 'workflow-server-test') }}
Expand Down Expand Up @@ -512,6 +515,7 @@ jobs:
WORKFLOW_PUBLIC_MANIFEST: '1'
WORKFLOW_TARGET_WORLD: "@workflow/world-postgres"
WORKFLOW_POSTGRES_URL: "postgres://world:world@localhost:5432/world"
WORKFLOW_NEXT_LAZY_DISCOVERY: ${{ matrix.app.lazyDiscovery == false && '0' || matrix.app.lazyDiscovery == true && '1' || '' }}

steps:
- name: Checkout Repo
Expand Down Expand Up @@ -557,7 +561,7 @@ jobs:
run: |
cd "${{ steps.prepare-workbench.outputs.workbench_app_path }}" && pnpm start &
echo "starting tests in 10 seconds" && sleep 10
pnpm run test:e2e --reporter=default --reporter=json --reporter=./packages/core/e2e/github-reporter.ts --outputFile=e2e-local-postgres-${{ matrix.app.name }}-${{ matrix.app.canary && 'canary' || 'stable' }}.json
pnpm run test:e2e --reporter=default --reporter=json --reporter=./packages/core/e2e/github-reporter.ts --outputFile=e2e-local-postgres-${{ matrix.app.name }}-${{ matrix.app.artifactSuffix }}.json
env:
NODE_OPTIONS: "--enable-source-maps"
APP_NAME: ${{ matrix.app.name }}
Expand All @@ -567,14 +571,14 @@ jobs:

- name: Generate E2E summary
if: always()
run: node .github/scripts/aggregate-e2e-results.js . --job-name "E2E Local Postgres (${{ matrix.app.name }})" >> $GITHUB_STEP_SUMMARY || true
run: node .github/scripts/aggregate-e2e-results.js . --job-name "E2E Local Postgres (${{ matrix.app.name }} - ${{ matrix.app.runLabel }})" >> $GITHUB_STEP_SUMMARY || true

- name: Upload E2E results
if: always()
uses: actions/upload-artifact@v4
with:
name: e2e-results-local-postgres-${{ matrix.app.name }}-${{ matrix.app.canary && 'canary' || 'stable' }}
path: e2e-local-postgres-${{ matrix.app.name }}-${{ matrix.app.canary && 'canary' || 'stable' }}.json
name: e2e-results-local-postgres-${{ matrix.app.name }}-${{ matrix.app.artifactSuffix }}
path: e2e-local-postgres-${{ matrix.app.name }}-${{ matrix.app.artifactSuffix }}.json
retention-days: 7
if-no-files-found: ignore

Expand Down
13 changes: 9 additions & 4 deletions packages/core/e2e/dev.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import fs from 'node:fs/promises';
import path from 'node:path';
import { afterEach, beforeAll, describe, expect, test } from 'vitest';
import { getWorkbenchAppPath } from './utils';
import {
getWorkbenchAppPath,
isNextLazyDiscoveryEnabledForTest,
} from './utils';

export interface DevTestConfig {
generatedStepPath: string;
Expand Down Expand Up @@ -44,9 +47,11 @@
);
const testWorkflowFile = finalConfig.testWorkflowFile ?? '3_streams.ts';
const workflowsDir = finalConfig.workflowsDir ?? 'workflows';
const supportsDeferredStepCopies = generatedStep.includes(
path.join('.well-known', 'workflow', 'v1', 'step', 'route.js')
);
const supportsDeferredStepCopies =
isNextLazyDiscoveryEnabledForTest() &&
generatedStep.includes(
path.join('.well-known', 'workflow', 'v1', 'step', 'route.js')
);
const restoreFiles: Array<{ path: string; content: string }> = [];

const fetchWithTimeout = (pathname: string) => {
Expand Down Expand Up @@ -127,7 +132,7 @@
: lastError
? ` Last error: ${String(lastError)}`
: '';
throw new Error(

Check failure on line 135 in packages/core/e2e/dev.test.ts

View workflow job for this annotation

GitHub Actions / E2E Local Dev Tests (hono - stable)

packages/core/e2e/dev.test.ts > dev e2e > should rebuild on adding workflow file

Error: Timed out after 50000ms waiting for generated workflow to include newWorkflowFile. Last error: expected '// biome-ignore-all lint: generated f…' to contain 'newWorkflowFile' ❯ pollUntil packages/core/e2e/dev.test.ts:135:13 ❯ packages/core/e2e/dev.test.ts:323:9
`Timed out after ${timeoutMs}ms waiting for ${description}.${lastErrorSuffix}`
);
};
Expand Down
10 changes: 8 additions & 2 deletions packages/core/e2e/local-build.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
import path from 'node:path';
import { describe, expect, test } from 'vitest';
import { usesVercelWorld } from '../../utils/src/world-target';
import { getWorkbenchAppPath } from './utils';
import {
getWorkbenchAppPath,
isNextLazyDiscoveryEnabledForTest,
} from './utils';

interface CommandResult {
stdout: string;
Expand Down Expand Up @@ -52,7 +55,7 @@
? `signal ${signal}`
: `exit code ${String(code)}`;
reject(
new Error(

Check failure on line 58 in packages/core/e2e/local-build.test.ts

View workflow job for this annotation

GitHub Actions / E2E Local Prod Tests (nextjs-turbopack - canary)

packages/core/e2e/local-build.test.ts > e2e > builds without errors

Error: Command "pnpm build" failed with exit code 1 > nextjs-turbopack@0.0.2-alpha.5 prebuild /tmp/workflow-nextjs-turbopack-ScaPSG/workbench/nextjs-turbopack > pnpm generate:workflows > nextjs-turbopack@0.0.2-alpha.5 generate:workflows /tmp/workflow-nextjs-turbopack-ScaPSG/workbench/nextjs-turbopack > node ../scripts/generate-workflows-registry.js ✓ Generated ./_workflows.ts with 19 workflow(s) - workflows/100_durable_agent_e2e.ts - workflows/10_single_stmt_control_flow.ts - workflows/1_simple.ts - workflows/2_control_flow.ts - workflows/3_streams.ts - workflows/4_ai.ts - workflows/5_hooks.ts - workflows/6_batching.ts - workflows/7_full.ts - workflows/8_react_render.tsx - workflows/96_many_steps.ts - workflows/97_bench.ts - workflows/98_duplicate_case.ts - workflows/99_e2e.ts - workflows/agent_chat.ts - workflows/serde-models.ts - workflows/serde-steps.ts - workflows/server_action_step_import_helpers.ts - workflows/server_action_step_imports.ts > nextjs-turbopack@0.0.2-alpha.5 build /tmp/workflow-nextjs-turbopack-ScaPSG/workbench/nextjs-turbopack > next build --turbopack Attention: Next.js now collects completely anonymous telemetry regarding usage. This information is used to shape Next.js' roadmap and prioritize features. You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL: https://nextjs.org/telemetry ▲ Next.js 16.2.1-canary.45 (Turbopack) - Experiments (use with caution): · deferredEntries · onBeforeDeferredEntries Creating an optimized production build ... FATAL: An unexpected Turbopack error occurred: failed to receive message Caused by: - reading packet length - unexpected end of file Debug info: - Execution of get_all_written_entrypoints_with_issues_operation failed - Execution of PlainIssue::from_issue failed - Execution of PlainSource::from_source failed - Execution of <WebpackLoadersProcessedAsset as Asset>::content failed - Execution of WebpackLoadersProcessedAsset::process failed - Execution of evaluate_webpack_loader failed - failed to receive message - reading packet length - unexpected end of file > Build error occurred Error [TurbopackInternalError]: failed to receive message Caused by: - reading packet length - unexpected end of file Debug info: - Execution of get_all_written_entrypoints_with_issues_operation failed - Execution of PlainIssue::from_issue failed - Execution of PlainSource::from_source failed - Execution of <WebpackLoadersProcessedAsset as Asset>::content failed - Execution of WebpackLoadersProcessedAsset::process failed - Execution of evaluate_webpack_loader failed - failed to receive message - reading packet length - unexpected end of file at <unknown> (TurbopackInternalError: failed to receive message) { type: 'TurbopackInternalError', location: undefined }  ELIFECYCLE  Command failed with exit code 1. ❯ ChildProcess.<anonymous> packages/core/e2e/local-build.test.ts:58:11

Check failure on line 58 in packages/core/e2e/local-build.test.ts

View workflow job for this annotation

GitHub Actions / E2E Local Prod Tests (nextjs-turbopack - stable lazyDiscovery disabled)

packages/core/e2e/local-build.test.ts > e2e > builds without errors

Error: Command "pnpm build" failed with exit code 1 > nextjs-turbopack@0.0.2-alpha.5 prebuild /tmp/workflow-nextjs-turbopack-AG8q5j/workbench/nextjs-turbopack > pnpm generate:workflows > nextjs-turbopack@0.0.2-alpha.5 generate:workflows /tmp/workflow-nextjs-turbopack-AG8q5j/workbench/nextjs-turbopack > node ../scripts/generate-workflows-registry.js ✓ Generated ./_workflows.ts with 19 workflow(s) - workflows/100_durable_agent_e2e.ts - workflows/10_single_stmt_control_flow.ts - workflows/1_simple.ts - workflows/2_control_flow.ts - workflows/3_streams.ts - workflows/4_ai.ts - workflows/5_hooks.ts - workflows/6_batching.ts - workflows/7_full.ts - workflows/8_react_render.tsx - workflows/96_many_steps.ts - workflows/97_bench.ts - workflows/98_duplicate_case.ts - workflows/99_e2e.ts - workflows/agent_chat.ts - workflows/serde-models.ts - workflows/serde-steps.ts - workflows/server_action_step_import_helpers.ts - workflows/server_action_step_imports.ts > nextjs-turbopack@0.0.2-alpha.5 build /tmp/workflow-nextjs-turbopack-AG8q5j/workbench/nextjs-turbopack > next build --turbopack Discovering workflow directives 2979ms ! esbuild warnings in steps bundle creation: Using direct eval with a bundler is not recommended and may cause problems at workflows/8_react_render.tsx:4:21 Created steps bundle 3964ms Created intermediate workflow bundle 398ms Creating webhook route Creating manifest... Created manifest with 122 steps, 104 workflows, and 8 classes 379ms ⚠ No build cache found. Please configure build caching for faster rebuilds. Read more: https://nextjs.org/docs/messages/no-cache Attention: Next.js now collects completely anonymous telemetry regarding usage. This information is used to shape Next.js' roadmap and prioritize features. You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL: https://nextjs.org/telemetry ▲ Next.js 16.2.1 (Turbopack) Creating an optimized production build ... Turbopack build encountered 3 warnings: ./workbench/nextjs-turbopack/app/.well-known/workflow/v1/step/route.js:43230:22 Module not found: Can't resolve 'cbor-extract' 43228 | try { 43229 | if (typeof __require == "function") extractor = require_cbor_extract(); > 43230 | else extractor = createRequire(import.meta.url)("cbor-extract"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 43231 | if (extractor) setExtractor(extractor.extractStrings); 43232 | } catch (error) { 43233 | } https://nextjs.org/docs/messages/module-not-found ./workbench/nextjs-turbopack/app/.well-known/workflow/v1/step/route.js:40052:15 Module not found: Can't resolve ('/ROOT/workbench/nextjs-turbopack/' <dynamic> | '/ROOT/workbench/nextjs-turbopack' <dynamic>) 40050 | const absolutePath = path11.resolve(process.cwd(), route.filePath); 40051 | try { > 40052 | await import(absolutePath); | ^^^^^^^^^^^^^^^^^^^^ 40053 | } catch (error) { 40054 | diagnostics.importFailures.push({ 40055 | filePath: route.filePath, https://nextjs.org/docs/messages/module-not-found ./workbench/nextjs-turbopack/next.config.ts Encountered unexpected file in NFT list A file was traced that indicates that the whole project was traced unintentionally. Somewhere in the import trace below, there are: - filesystem operations (like path.join, path.resolve or fs.readFile), or - very dynamic requires (like require('./' + foo)). To resolve this, you can - remove them if possible, or - only use them in development, or - make sure they are statically scoped to some subfolder: path.join(process.cwd(), 'data', bar), or - add ignore comments: path.join(/*turbopackIgnore: true*/ process.cwd(), bar) Import trace: App Route: ./workbench/nextjs-turbopack/next.config.ts ./workbench/nextjs-turbopack/app/.well-known/workflow/v1/step/route.js > Build error occurred Error: Turbopack build failed with 2 errors: ./workbench/nextjs-turbop

Check failure on line 58 in packages/core/e2e/local-build.test.ts

View workflow job for this annotation

GitHub Actions / E2E Local Postgres Tests (nextjs-turbopack - stable lazyDiscovery disabled)

packages/core/e2e/local-build.test.ts > e2e > builds without errors

Error: Command "pnpm build" failed with exit code 1 > nextjs-turbopack@0.0.2-alpha.5 prebuild /tmp/workflow-nextjs-turbopack-48sSN8/workbench/nextjs-turbopack > pnpm generate:workflows > nextjs-turbopack@0.0.2-alpha.5 generate:workflows /tmp/workflow-nextjs-turbopack-48sSN8/workbench/nextjs-turbopack > node ../scripts/generate-workflows-registry.js ✓ Generated ./_workflows.ts with 19 workflow(s) - workflows/100_durable_agent_e2e.ts - workflows/10_single_stmt_control_flow.ts - workflows/1_simple.ts - workflows/2_control_flow.ts - workflows/3_streams.ts - workflows/4_ai.ts - workflows/5_hooks.ts - workflows/6_batching.ts - workflows/7_full.ts - workflows/8_react_render.tsx - workflows/96_many_steps.ts - workflows/97_bench.ts - workflows/98_duplicate_case.ts - workflows/99_e2e.ts - workflows/agent_chat.ts - workflows/serde-models.ts - workflows/serde-steps.ts - workflows/server_action_step_import_helpers.ts - workflows/server_action_step_imports.ts > nextjs-turbopack@0.0.2-alpha.5 build /tmp/workflow-nextjs-turbopack-48sSN8/workbench/nextjs-turbopack > next build --turbopack Discovering workflow directives 2929ms ! esbuild warnings in steps bundle creation: Using direct eval with a bundler is not recommended and may cause problems at workflows/8_react_render.tsx:4:21 Created steps bundle 3904ms Created intermediate workflow bundle 430ms Creating webhook route Creating manifest... Created manifest with 122 steps, 104 workflows, and 8 classes 382ms ⚠ No build cache found. Please configure build caching for faster rebuilds. Read more: https://nextjs.org/docs/messages/no-cache Attention: Next.js now collects completely anonymous telemetry regarding usage. This information is used to shape Next.js' roadmap and prioritize features. You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL: https://nextjs.org/telemetry ▲ Next.js 16.2.1 (Turbopack) Creating an optimized production build ... Turbopack build encountered 3 warnings: ./workbench/nextjs-turbopack/app/.well-known/workflow/v1/step/route.js:43230:22 Module not found: Can't resolve 'cbor-extract' 43228 | try { 43229 | if (typeof __require == "function") extractor = require_cbor_extract(); > 43230 | else extractor = createRequire(import.meta.url)("cbor-extract"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 43231 | if (extractor) setExtractor(extractor.extractStrings); 43232 | } catch (error) { 43233 | } https://nextjs.org/docs/messages/module-not-found ./workbench/nextjs-turbopack/app/.well-known/workflow/v1/step/route.js:40052:15 Module not found: Can't resolve ('/ROOT/workbench/nextjs-turbopack/' <dynamic> | '/ROOT/workbench/nextjs-turbopack' <dynamic>) 40050 | const absolutePath = path11.resolve(process.cwd(), route.filePath); 40051 | try { > 40052 | await import(absolutePath); | ^^^^^^^^^^^^^^^^^^^^ 40053 | } catch (error) { 40054 | diagnostics.importFailures.push({ 40055 | filePath: route.filePath, https://nextjs.org/docs/messages/module-not-found ./workbench/nextjs-turbopack/next.config.ts Encountered unexpected file in NFT list A file was traced that indicates that the whole project was traced unintentionally. Somewhere in the import trace below, there are: - filesystem operations (like path.join, path.resolve or fs.readFile), or - very dynamic requires (like require('./' + foo)). To resolve this, you can - remove them if possible, or - only use them in development, or - make sure they are statically scoped to some subfolder: path.join(process.cwd(), 'data', bar), or - add ignore comments: path.join(/*turbopackIgnore: true*/ process.cwd(), bar) Import trace: App Route: ./workbench/nextjs-turbopack/next.config.ts ./workbench/nextjs-turbopack/app/.well-known/workflow/v1/step/route.js > Build error occurred Error: Turbopack build failed with 2 errors: ./workbench/nextjs-turbop

Check failure on line 58 in packages/core/e2e/local-build.test.ts

View workflow job for this annotation

GitHub Actions / E2E Local Prod Tests (nextjs-webpack - stable lazyDiscovery disabled)

packages/core/e2e/local-build.test.ts > e2e > builds without errors

Error: Command "pnpm build" failed with exit code 1 > nextjs-webpack@0.0.2-alpha.5 prebuild /tmp/workflow-nextjs-webpack-Q370v1/workbench/nextjs-webpack > pnpm generate:workflows > nextjs-webpack@0.0.2-alpha.5 generate:workflows /tmp/workflow-nextjs-webpack-Q370v1/workbench/nextjs-webpack > node ../scripts/generate-workflows-registry.js ✓ Generated ./_workflows.ts with 15 workflow(s) - workflows/100_durable_agent_e2e.ts - workflows/10_single_stmt_control_flow.ts - workflows/1_simple.ts - workflows/2_control_flow.ts - workflows/3_streams.ts - workflows/4_ai.ts - workflows/5_hooks.ts - workflows/6_batching.ts - workflows/7_full.ts - workflows/8_react_render.tsx - workflows/98_duplicate_case.ts - workflows/99_e2e.ts - workflows/agent_chat.ts - workflows/serde-models.ts - workflows/serde-steps.ts > nextjs-webpack@0.0.2-alpha.5 build /tmp/workflow-nextjs-webpack-Q370v1/workbench/nextjs-webpack > next build --webpack Discovering workflow directives 3049ms ! esbuild warnings in steps bundle creation: Using direct eval with a bundler is not recommended and may cause problems at workflows/8_react_render.tsx:4:21 Created steps bundle 3991ms Created intermediate workflow bundle 404ms Creating webhook route Creating manifest... Created manifest with 111 steps, 90 workflows, and 8 classes 423ms ⚠ No build cache found. Please configure build caching for faster rebuilds. Read more: https://nextjs.org/docs/messages/no-cache Attention: Next.js now collects completely anonymous telemetry regarding usage. This information is used to shape Next.js' roadmap and prioritize features. You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL: https://nextjs.org/telemetry ▲ Next.js 16.2.1 (webpack) - Experiments (use with caution): ⨯ serverMinification Creating an optimized production build ... ⚠ Compiled with warnings in 23.7s ./app/.well-known/workflow/v1/step/route.js Critical dependency: the request of a dependency is an expression Import trace for requested module: ./app/.well-known/workflow/v1/step/route.js ./app/.well-known/workflow/v1/step/route.js module.createRequire failed parsing argument. Import trace for requested module: ./app/.well-known/workflow/v1/step/route.js ./node_modules/.pnpm/@vercel+queue@0.1.4/node_modules/@vercel/queue/dist/index.mjs Critical dependency: the request of a dependency is an expression Import trace for requested module: ./node_modules/.pnpm/@vercel+queue@0.1.4/node_modules/@vercel/queue/dist/index.mjs ./node_modules/.pnpm/@workflow+world-vercel@file+..+..+tarballs+workflow-world-vercel-5.0.0-beta.1.tgz_@opentelemetry+api@1.9.1/node_modules/@workflow/world-vercel/dist/queue.js ./node_modules/.pnpm/@workflow+world-vercel@file+..+..+tarballs+workflow-world-vercel-5.0.0-beta.1.tgz_@opentelemetry+api@1.9.1/node_modules/@workflow/world-vercel/dist/index.js ./node_modules/.pnpm/@workflow+core@file+..+..+tarballs+workflow-core-5.0.0-beta.1.tgz_@opentelemetry+api@1.9.1/node_modules/@workflow/core/dist/runtime/world.js ./node_modules/.pnpm/@workflow+core@file+..+..+tarballs+workflow-core-5.0.0-beta.1.tgz_@opentelemetry+api@1.9.1/node_modules/@workflow/core/dist/runtime.js ./node_modules/.pnpm/workflow@file+..+..+tarballs+workflow-5.0.0-beta.1.tgz_@nestjs+common@11.1.19_reflect-m_0d45f462fb47f2754c5520f609a9da0a/node_modules/workflow/dist/runtime.js ./app/.well-known/workflow/v1/flow/route.js Running TypeScript ... Finished TypeScript in 6.4s ... Collecting page data using 3 workers ... Error: Dynamic require of "tty" is not supported at <unknown> (.next/server/app/.well-known/workflow/v1/step/route.js:3256:11) at node_modules/.pnpm/debug@4.4.3_supports-color@8.1.1/node_modules/debug/src/node.js (.next/server/app/.well-known/workflow/v1/step/route.js:4760:19) at __require2 (.next/server/app/.well-known/workflow/v1/step/route.js:3262:56) at node_modules/.pnpm/debug@4.4.3_supports-color@8.1.1/node_modules/debug/src/index.js (.next/server/app/.well-known/wor

Check failure on line 58 in packages/core/e2e/local-build.test.ts

View workflow job for this annotation

GitHub Actions / E2E Local Postgres Tests (nextjs-webpack - stable lazyDiscovery disabled)

packages/core/e2e/local-build.test.ts > e2e > builds without errors

Error: Command "pnpm build" failed with exit code 1 > nextjs-webpack@0.0.2-alpha.5 prebuild /tmp/workflow-nextjs-webpack-fy2RY8/workbench/nextjs-webpack > pnpm generate:workflows > nextjs-webpack@0.0.2-alpha.5 generate:workflows /tmp/workflow-nextjs-webpack-fy2RY8/workbench/nextjs-webpack > node ../scripts/generate-workflows-registry.js ✓ Generated ./_workflows.ts with 15 workflow(s) - workflows/100_durable_agent_e2e.ts - workflows/10_single_stmt_control_flow.ts - workflows/1_simple.ts - workflows/2_control_flow.ts - workflows/3_streams.ts - workflows/4_ai.ts - workflows/5_hooks.ts - workflows/6_batching.ts - workflows/7_full.ts - workflows/8_react_render.tsx - workflows/98_duplicate_case.ts - workflows/99_e2e.ts - workflows/agent_chat.ts - workflows/serde-models.ts - workflows/serde-steps.ts > nextjs-webpack@0.0.2-alpha.5 build /tmp/workflow-nextjs-webpack-fy2RY8/workbench/nextjs-webpack > next build --webpack Discovering workflow directives 3030ms ! esbuild warnings in steps bundle creation: Using direct eval with a bundler is not recommended and may cause problems at workflows/8_react_render.tsx:4:21 Created steps bundle 3934ms Created intermediate workflow bundle 418ms Creating webhook route Creating manifest... Created manifest with 111 steps, 90 workflows, and 8 classes 374ms ⚠ No build cache found. Please configure build caching for faster rebuilds. Read more: https://nextjs.org/docs/messages/no-cache Attention: Next.js now collects completely anonymous telemetry regarding usage. This information is used to shape Next.js' roadmap and prioritize features. You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL: https://nextjs.org/telemetry ▲ Next.js 16.2.1 (webpack) - Experiments (use with caution): ⨯ serverMinification Creating an optimized production build ... ⚠ Compiled with warnings in 25.2s ./app/.well-known/workflow/v1/step/route.js Critical dependency: the request of a dependency is an expression Import trace for requested module: ./app/.well-known/workflow/v1/step/route.js ./app/.well-known/workflow/v1/step/route.js module.createRequire failed parsing argument. Import trace for requested module: ./app/.well-known/workflow/v1/step/route.js ./node_modules/.pnpm/@vercel+queue@0.1.4/node_modules/@vercel/queue/dist/index.mjs Critical dependency: the request of a dependency is an expression Import trace for requested module: ./node_modules/.pnpm/@vercel+queue@0.1.4/node_modules/@vercel/queue/dist/index.mjs ./node_modules/.pnpm/@workflow+world-vercel@file+..+..+tarballs+workflow-world-vercel-5.0.0-beta.1.tgz_@opentelemetry+api@1.9.1/node_modules/@workflow/world-vercel/dist/queue.js ./node_modules/.pnpm/@workflow+world-vercel@file+..+..+tarballs+workflow-world-vercel-5.0.0-beta.1.tgz_@opentelemetry+api@1.9.1/node_modules/@workflow/world-vercel/dist/index.js ./node_modules/.pnpm/@workflow+core@file+..+..+tarballs+workflow-core-5.0.0-beta.1.tgz_@opentelemetry+api@1.9.1/node_modules/@workflow/core/dist/runtime/world.js ./node_modules/.pnpm/@workflow+core@file+..+..+tarballs+workflow-core-5.0.0-beta.1.tgz_@opentelemetry+api@1.9.1/node_modules/@workflow/core/dist/runtime.js ./node_modules/.pnpm/workflow@file+..+..+tarballs+workflow-5.0.0-beta.1.tgz_@nestjs+common@11.1.19_reflect-m_0d45f462fb47f2754c5520f609a9da0a/node_modules/workflow/dist/api.js ./app/api/chat/route.ts Running TypeScript ... Finished TypeScript in 6.5s ... Collecting page data using 3 workers ... Error: Dynamic require of "tty" is not supported at <unknown> (.next/server/app/.well-known/workflow/v1/step/route.js:2853:11) at node_modules/.pnpm/debug@4.4.3_supports-color@8.1.1/node_modules/debug/src/node.js (.next/server/app/.well-known/workflow/v1/step/route.js:4357:19) at __require2 (.next/server/app/.well-known/workflow/v1/step/route.js:2859:56) at node_modules/.pnpm/debug@4.4.3_supports-color@8.1.1/node_modules/debug/src/index.js (.next/server/app/.well-known/workflow/v1/step/route.js:4
`Command "${command} ${args.join(' ')}" failed with ${exitInfo}\n${output}`
)
);
Expand Down Expand Up @@ -119,7 +122,10 @@

expect(result.output).not.toContain('Error:');

if (DEFERRED_BUILD_MODE_PROJECTS.has(project)) {
if (
DEFERRED_BUILD_MODE_PROJECTS.has(project) &&
isNextLazyDiscoveryEnabledForTest()
) {
const deferredBuildSupported = !result.output.includes(
DEFERRED_BUILD_UNSUPPORTED_WARNING
);
Expand Down
5 changes: 5 additions & 0 deletions packages/core/e2e/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { setTimeout as sleep } from 'node:timers/promises';
import { fileURLToPath } from 'node:url';
import { createVercelWorld } from '@workflow/world-vercel';
import { onTestFailed } from 'vitest';
import { parseEnvironmentFlag } from '../../next/src/environment-flag.js';
import type { Run } from '../src/runtime';
import { getWorld, setWorld } from '../src/runtime';

Expand All @@ -19,6 +20,10 @@ function splitArgs(raw: string): string[] {
return value.split(/\s+/);
}

export function isNextLazyDiscoveryEnabledForTest(): boolean {
return parseEnvironmentFlag(process.env.WORKFLOW_NEXT_LAZY_DISCOVERY) ?? true;
}

export function getWorkbenchAppPath(overrideAppName?: string): string {
const explicitWorkbenchPath = process.env.WORKBENCH_APP_PATH;
const appName = process.env.APP_NAME ?? overrideAppName;
Expand Down
42 changes: 42 additions & 0 deletions packages/next/src/builder.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { afterEach, describe, expect, it } from 'vitest';
import { shouldUseDeferredBuilder } from './builder.js';
import { parseEnvironmentFlag } from './environment-flag.js';

const originalLazyDiscoveryEnv = process.env.WORKFLOW_NEXT_LAZY_DISCOVERY;

afterEach(() => {
if (originalLazyDiscoveryEnv === undefined) {
delete process.env.WORKFLOW_NEXT_LAZY_DISCOVERY;
} else {
process.env.WORKFLOW_NEXT_LAZY_DISCOVERY = originalLazyDiscoveryEnv;
}
});

describe('shouldUseDeferredBuilder', () => {
it('treats WORKFLOW_NEXT_LAZY_DISCOVERY=0 as disabled', () => {
process.env.WORKFLOW_NEXT_LAZY_DISCOVERY = '0';

expect(shouldUseDeferredBuilder('16.2.1')).toBe(false);
});

it('treats WORKFLOW_NEXT_LAZY_DISCOVERY=false as disabled', () => {
process.env.WORKFLOW_NEXT_LAZY_DISCOVERY = 'false';

expect(shouldUseDeferredBuilder('16.2.1')).toBe(false);
});

it('treats WORKFLOW_NEXT_LAZY_DISCOVERY=off as disabled', () => {
process.env.WORKFLOW_NEXT_LAZY_DISCOVERY = 'off';

expect(parseEnvironmentFlag(process.env.WORKFLOW_NEXT_LAZY_DISCOVERY)).toBe(
false
);
expect(shouldUseDeferredBuilder('16.2.1')).toBe(false);
});

it('enables deferred mode for compatible versions when the env is enabled', () => {
process.env.WORKFLOW_NEXT_LAZY_DISCOVERY = '1';

expect(shouldUseDeferredBuilder('16.2.1')).toBe(true);
});
});
4 changes: 3 additions & 1 deletion packages/next/src/builder.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import semver from 'semver';
import { getNextBuilderDeferred } from './builder-deferred.js';
import { getNextBuilderEager } from './builder-eager.js';
import { parseEnvironmentFlag } from './environment-flag.js';

export const DEFERRED_BUILDER_MIN_VERSION = '16.2.0-canary.48';

Expand All @@ -13,7 +14,8 @@ export const WORKFLOW_DEFERRED_ENTRIES = [
let warnedAboutFlagAndVersion = false;

export function shouldUseDeferredBuilder(nextVersion: string): boolean {
const flagEnabled = Boolean(process.env.WORKFLOW_NEXT_LAZY_DISCOVERY);
const flagEnabled =
parseEnvironmentFlag(process.env.WORKFLOW_NEXT_LAZY_DISCOVERY) ?? false;
const versionCompatible = semver.gte(
nextVersion,
DEFERRED_BUILDER_MIN_VERSION
Expand Down
16 changes: 16 additions & 0 deletions packages/next/src/environment-flag.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const FALSE_ENV_VALUES = new Set(['0', 'false', 'no', 'off']);

export function parseEnvironmentFlag(
rawValue: string | undefined
): boolean | undefined {
const normalizedValue = rawValue?.trim().toLowerCase();
if (!normalizedValue) {
return undefined;
}

if (FALSE_ENV_VALUES.has(normalizedValue)) {
return false;
}

return true;
}
30 changes: 30 additions & 0 deletions packages/next/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,34 @@ describe('withWorkflow outputFileTracingRoot', () => {
workingDir: process.cwd(),
});
});

it('preserves an explicit lazyDiscovery disable override', () => {
process.env.WORKFLOW_NEXT_LAZY_DISCOVERY = '0';

withWorkflow(
{},
{
workflows: {
lazyDiscovery: true,
},
}
);

expect(process.env.WORKFLOW_NEXT_LAZY_DISCOVERY).toBe('0');
});

it('treats an empty lazyDiscovery env override as unset', () => {
process.env.WORKFLOW_NEXT_LAZY_DISCOVERY = '';

withWorkflow(
{},
{
workflows: {
lazyDiscovery: true,
},
}
);

expect(process.env.WORKFLOW_NEXT_LAZY_DISCOVERY).toBe('1');
});
});
14 changes: 12 additions & 2 deletions packages/next/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { NextConfig } from 'next';
import semver from 'semver';
import { parseEnvironmentFlag } from './environment-flag.js';
import {
getNextBuilder,
shouldUseDeferredBuilder,
Expand Down Expand Up @@ -61,8 +62,17 @@ export function withWorkflow(
};
} = {}
) {
if (workflows?.lazyDiscovery) {
process.env.WORKFLOW_NEXT_LAZY_DISCOVERY = '1';
const lazyDiscoveryOverride = parseEnvironmentFlag(
process.env.WORKFLOW_NEXT_LAZY_DISCOVERY
);
if (lazyDiscoveryOverride === undefined) {
if (workflows?.lazyDiscovery) {
process.env.WORKFLOW_NEXT_LAZY_DISCOVERY = '1';
}
} else {
process.env.WORKFLOW_NEXT_LAZY_DISCOVERY = lazyDiscoveryOverride
? '1'
: '0';
}

if (!process.env.VERCEL_DEPLOYMENT_ID) {
Expand Down
15 changes: 10 additions & 5 deletions packages/next/src/loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { readFile } from 'node:fs/promises';
import { connect, type Socket } from 'node:net';
import { dirname, join, relative } from 'node:path';
import { transform } from '@swc/core';
import { parseEnvironmentFlag } from './environment-flag.js';
import {
parseMessage,
type SocketMessage,
Expand Down Expand Up @@ -687,11 +688,15 @@ export default function workflowLoader(

// Detect workflow patterns in the source code.
const patterns = await detectPatterns(sourceForTransform);
// Always notify discovery tracking, even for `false/false`, so files that
// previously had workflow/step usage are removed from the tracked sets.
// Deferred step copy files must report using their original source path so
// deferred rebuilds can react to source edits outside generated artifacts.
if (!isDeferredStepCopyFile || deferredStepSourceMetadata?.absolutePath) {
const shouldTrackDeferredDiscovery =
parseEnvironmentFlag(process.env.WORKFLOW_NEXT_LAZY_DISCOVERY) ?? false;

// Discovery tracking is only needed for deferred builds. Eager builds
// discover inputs up front and should ignore any stale socket metadata.
if (
shouldTrackDeferredDiscovery &&
(!isDeferredStepCopyFile || deferredStepSourceMetadata?.absolutePath)
) {
const hasSerde = patterns.hasSerde;
const nextPatternState: DiscoveredPatternState = {
hasWorkflow: patterns.hasUseWorkflow,
Expand Down
Loading
Loading