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
19 changes: 19 additions & 0 deletions .github/workflows/build_and_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ jobs:
export TURBOPACK_DEV=1
export NEXT_TEST_MODE=dev
export NEXT_TEST_REACT_VERSION="${{ matrix.react }}"
export __NEXT_EXPERIMENTAL_STRICT_ROUTE_TYPES=true

node run-tests.js \
--test-pattern '^(test\/(development|e2e))/.*\.test\.(js|jsx|ts|tsx)$' \
Expand Down Expand Up @@ -279,6 +280,7 @@ jobs:
export IS_TURBOPACK_TEST=1
export TURBOPACK_DEV=1
export NEXT_TEST_REACT_VERSION="${{ matrix.react }}"
export __NEXT_EXPERIMENTAL_STRICT_ROUTE_TYPES=true

node run-tests.js \
--timings \
Expand Down Expand Up @@ -309,6 +311,7 @@ jobs:
export TURBOPACK_BUILD=1
export NEXT_TEST_MODE=start
export NEXT_TEST_REACT_VERSION="${{ matrix.react }}"
export __NEXT_EXPERIMENTAL_STRICT_ROUTE_TYPES=true

node run-tests.js --timings -g ${{ matrix.group }} --type production
stepName: 'test-turbopack-production-react-${{ matrix.react }}-${{ matrix.group }}'
Expand Down Expand Up @@ -336,6 +339,7 @@ jobs:
export IS_TURBOPACK_TEST=1
export TURBOPACK_BUILD=1
export NEXT_TEST_REACT_VERSION="${{ matrix.react }}"
export __NEXT_EXPERIMENTAL_STRICT_ROUTE_TYPES=true

node run-tests.js \
--timings \
Expand Down Expand Up @@ -363,6 +367,7 @@ jobs:
export NEXT_EXTERNAL_TESTS_FILTERS="$(pwd)/test/rspack-dev-tests-manifest.json"
export NEXT_TEST_MODE=dev
export NEXT_TEST_REACT_VERSION="${{ matrix.react }}"
export __NEXT_EXPERIMENTAL_STRICT_ROUTE_TYPES=true

# rspack flags
export NEXT_RSPACK=1
Expand Down Expand Up @@ -399,6 +404,7 @@ jobs:
afterBuild: |
export NEXT_EXTERNAL_TESTS_FILTERS="$(pwd)/test/rspack-dev-tests-manifest.json"
export NEXT_TEST_REACT_VERSION="${{ matrix.react }}"
export __NEXT_EXPERIMENTAL_STRICT_ROUTE_TYPES=true

# rspack flags
export NEXT_RSPACK=1
Expand Down Expand Up @@ -435,6 +441,7 @@ jobs:
export NEXT_EXTERNAL_TESTS_FILTERS="$(pwd)/test/rspack-build-tests-manifest.json"
export NEXT_TEST_MODE=start
export NEXT_TEST_REACT_VERSION="${{ matrix.react }}"
export __NEXT_EXPERIMENTAL_STRICT_ROUTE_TYPES=true

# rspack flags
export NEXT_RSPACK=1
Expand Down Expand Up @@ -468,6 +475,7 @@ jobs:
afterBuild: |
export NEXT_EXTERNAL_TESTS_FILTERS="$(pwd)/test/rspack-build-tests-manifest.json"
export NEXT_TEST_REACT_VERSION="${{ matrix.react }}"
export __NEXT_EXPERIMENTAL_STRICT_ROUTE_TYPES=true

# rspack flags
export NEXT_RSPACK=1
Expand Down Expand Up @@ -562,6 +570,7 @@ jobs:
nodeVersion: ${{ matrix.node }}
afterBuild: |
export __NEXT_NODE_NATIVE_TS_LOADER_ENABLED=true
export __NEXT_EXPERIMENTAL_STRICT_ROUTE_TYPES=true
NEXT_TEST_MODE=dev NODE_OPTIONS=--experimental-transform-types node run-tests.js test/e2e/app-dir/next-config-ts-native-ts/**/*.test.ts test/e2e/app-dir/next-config-ts-native-mts/**/*.test.ts
stepName: 'test-next-config-ts-native-ts-dev-${{ matrix.node }}'

Expand All @@ -583,6 +592,7 @@ jobs:
nodeVersion: ${{ matrix.node }}
afterBuild: |
export __NEXT_NODE_NATIVE_TS_LOADER_ENABLED=true
export __NEXT_EXPERIMENTAL_STRICT_ROUTE_TYPES=true
NEXT_TEST_MODE=start NODE_OPTIONS=--experimental-transform-types node run-tests.js test/e2e/app-dir/next-config-ts-native-ts/**/*.test.ts test/e2e/app-dir/next-config-ts-native-mts/**/*.test.ts
stepName: 'test-next-config-ts-native-ts-prod-${{ matrix.node }}'

Expand Down Expand Up @@ -623,6 +633,7 @@ jobs:
uses: ./.github/workflows/build_reusable.yml
with:
afterBuild: |
export __NEXT_EXPERIMENTAL_STRICT_ROUTE_TYPES=true
node scripts/test-new-tests.mjs \
--flake-detection \
--mode dev \
Expand All @@ -647,6 +658,7 @@ jobs:
uses: ./.github/workflows/build_reusable.yml
with:
afterBuild: |
export __NEXT_EXPERIMENTAL_STRICT_ROUTE_TYPES=true
node scripts/test-new-tests.mjs \
--flake-detection \
--mode start \
Expand All @@ -672,6 +684,7 @@ jobs:
with:
afterBuild: |
export NEXT_E2E_TEST_TIMEOUT=240000
export __NEXT_EXPERIMENTAL_STRICT_ROUTE_TYPES=true
export GH_PR_NUMBER=${{ github.event.pull_request && github.event.pull_request.number || '' }}
node scripts/test-new-tests.mjs \
--mode deploy \
Expand Down Expand Up @@ -733,6 +746,7 @@ jobs:
export IS_WEBPACK_TEST=1
export NEXT_TEST_MODE=dev
export NEXT_TEST_REACT_VERSION="${{ matrix.react }}"
export __NEXT_EXPERIMENTAL_STRICT_ROUTE_TYPES=true

node run-tests.js \
--timings \
Expand All @@ -759,6 +773,7 @@ jobs:
afterBuild: |
export NEXT_TEST_MODE=dev
export IS_WEBPACK_TEST=1
export __NEXT_EXPERIMENTAL_STRICT_ROUTE_TYPES=true

node run-tests.js \
test/e2e/app-dir/app/index.test.ts \
Expand Down Expand Up @@ -787,6 +802,7 @@ jobs:
nodeVersion: 20.9.0
afterBuild: |
export IS_WEBPACK_TEST=1
export __NEXT_EXPERIMENTAL_STRICT_ROUTE_TYPES=true
node run-tests.js \
--concurrency 4 \
test/production/pages-dir/production/test/index.test.ts \
Expand Down Expand Up @@ -816,6 +832,7 @@ jobs:
afterBuild: |
export NEXT_TEST_MODE=start
export IS_WEBPACK_TEST=1
export __NEXT_EXPERIMENTAL_STRICT_ROUTE_TYPES=true

node run-tests.js --type production \
test/e2e/app-dir/app/index.test.ts \
Expand Down Expand Up @@ -848,6 +865,7 @@ jobs:
export IS_WEBPACK_TEST=1
export NEXT_TEST_MODE=start
export NEXT_TEST_REACT_VERSION="${{ matrix.react }}"
export __NEXT_EXPERIMENTAL_STRICT_ROUTE_TYPES=true

node run-tests.js --timings -g ${{ matrix.group }} --type production
stepName: 'test-prod-react-${{ matrix.react }}-${{ matrix.group }}'
Expand Down Expand Up @@ -887,6 +905,7 @@ jobs:
afterBuild: |
export IS_WEBPACK_TEST=1
export NEXT_TEST_REACT_VERSION="${{ matrix.react }}"
export __NEXT_EXPERIMENTAL_STRICT_ROUTE_TYPES=true

node run-tests.js \
--timings \
Expand Down
6 changes: 5 additions & 1 deletion packages/next/src/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1483,7 +1483,11 @@ export default async function build(
routeTypesFilePath,
config
)
await writeValidatorFile(routeTypesManifest, validatorFilePath)
await writeValidatorFile(
routeTypesManifest,
validatorFilePath,
Boolean(config.experimental.strictRouteTypes)
)
})

// Turbopack already handles conflicting app and page routes.
Expand Down
6 changes: 5 additions & 1 deletion packages/next/src/cli/next-typegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,11 @@ const nextTypegen = async (
nextConfig
)

await writeValidatorFile(routeTypesManifest, validatorFilePath)
await writeValidatorFile(
routeTypesManifest,
validatorFilePath,
Boolean(nextConfig.experimental.strictRouteTypes)
)

// Generate cache-life types if cacheLife config exists
const cacheLifeFilePath = join(distDir, 'types', 'cache-life.d.ts')
Expand Down
1 change: 1 addition & 0 deletions packages/next/src/server/config-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ export const experimentalSchema = {
turbopackInferModuleSideEffects: z.boolean().optional(),
optimizePackageImports: z.array(z.string()).optional(),
optimizeServerReact: z.boolean().optional(),
strictRouteTypes: z.boolean().optional(),
clientTraceMetadata: z.array(z.string()).optional(),
serverMinification: z.boolean().optional(),
serverSourceMaps: z.boolean().optional(),
Expand Down
7 changes: 7 additions & 0 deletions packages/next/src/server/config-shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,12 @@ export interface ExperimentalConfig {
*/
optimizeServerReact?: boolean

/**
* Type-checks props and return values of pages.
* Requires literal values for segment config (e.g. `export const dynamic = 'force-static' as const`).
*/
strictRouteTypes?: boolean

/**
* Displays an indicator when a React Transition has no other indicator rendered.
* This includes displaying an indicator on client-side navigations.
Expand Down Expand Up @@ -1548,6 +1554,7 @@ export const defaultConfig = Object.freeze({
webpackBuildWorker: undefined,
webpackMemoryOptimizations: false,
optimizeServerReact: true,
strictRouteTypes: false,
viewTransition: false,
removeUncaughtErrorAndRejectionListeners: false,
validateRSCRequestHeaders: !!(
Expand Down
19 changes: 19 additions & 0 deletions packages/next/src/server/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1888,6 +1888,25 @@ function enforceExperimentalFeatures(
}
}

// TODO: Remove this once strictRouteTypes is the default.
if (
process.env.__NEXT_EXPERIMENTAL_STRICT_ROUTE_TYPES === 'true' &&
// We do respect an explicit value in the user config.
(config.experimental.strictRouteTypes === undefined ||
(isDefaultConfig && !config.experimental.strictRouteTypes))
) {
config.experimental.strictRouteTypes = true

if (configuredExperimentalFeatures) {
addConfiguredExperimentalFeature(
configuredExperimentalFeatures,
'strictRouteTypes',
true,
'enabled by `__NEXT_EXPERIMENTAL_STRICT_ROUTE_TYPES`'
)
}
}
Comment on lines +1891 to +1908
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The strictRouteTypes feature is being enabled for Rspack in CI, but according to the PR description and test expectations, it should not be enabled for Cache Component shards (Rspack).

View Details
📝 Patch Details
diff --git a/packages/next/src/server/config.ts b/packages/next/src/server/config.ts
index 83c7e69a03..52dd9750dc 100644
--- a/packages/next/src/server/config.ts
+++ b/packages/next/src/server/config.ts
@@ -1891,6 +1891,7 @@ function enforceExperimentalFeatures(
   // TODO: Remove this once strictRouteTypes is the default.
   if (
     process.env.__NEXT_EXPERIMENTAL_STRICT_ROUTE_TYPES === 'true' &&
+    !process.env.NEXT_RSPACK &&
     // We do respect an explicit value in the user config.
     (config.experimental.strictRouteTypes === undefined ||
       (isDefaultConfig && !config.experimental.strictRouteTypes))

Analysis

strictRouteTypes feature incorrectly enabled for Rspack builds

What fails: The strictRouteTypes experimental feature is enabled for Rspack bundler via __NEXT_EXPERIMENTAL_STRICT_ROUTE_TYPES=true environment variable, but Rspack should be excluded per the test expectations.

How to reproduce:

export __NEXT_EXPERIMENTAL_STRICT_ROUTE_TYPES=true
export NEXT_RSPACK=1
npm run build test/production/app-dir/build-output-prerender

Expected behavior: Rspack preamble output should NOT include strictRouteTypes in the experimental flags list:

▲ Next.js x.y.z (Rspack, Cache Components)

Actual behavior: The feature gets enabled anyway because the condition in enforceExperimentalFeatures() doesn't check for Rspack.

Root cause: Lines 1891-1908 in packages/next/src/server/config.ts lack a check to exclude Rspack from the feature enablement. The PR that added this feature (60b5e591a5) intentionally excluded Rspack from showing this flag in tests (see test/production/app-dir/build-output-prerender/build-output-prerender.test.ts lines 55-58) but the implementation didn't enforce this exclusion.

Fix: Added !process.env.NEXT_RSPACK to the condition that enables the feature, aligning the implementation with the documented test expectations.

References:


if (
process.env.__NEXT_EXPERIMENTAL_TRANSITION_INDICATOR === 'true' &&
// We do respect an explicit value in the user config.
Expand Down
19 changes: 16 additions & 3 deletions packages/next/src/server/lib/router-utils/route-types-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {
generateRouteTypesFile,
generateLinkTypesFile,
generateValidatorFile,
generateValidatorFileStrict,
generateRouteTypesFileStrict,
} from './typegen'
import { tryToParsePath } from '../../../lib/try-to-parse-path'
import {
Expand Down Expand Up @@ -361,7 +363,12 @@ export async function writeRouteTypesManifest(
}

// Write the main routes.d.ts file
await fs.promises.writeFile(filePath, generateRouteTypesFile(manifest))
await fs.promises.writeFile(
filePath,
config.experimental.strictRouteTypes
? generateRouteTypesFileStrict(manifest)
: generateRouteTypesFile(manifest)
)

// Write the link.d.ts file if typedRoutes is enabled
if (config.typedRoutes === true) {
Expand All @@ -372,13 +379,19 @@ export async function writeRouteTypesManifest(

export async function writeValidatorFile(
manifest: RouteTypesManifest,
filePath: string
filePath: string,
strict: boolean
) {
const dirname = path.dirname(filePath)

if (!fs.existsSync(dirname)) {
await fs.promises.mkdir(dirname, { recursive: true })
}

await fs.promises.writeFile(filePath, generateValidatorFile(manifest))
await fs.promises.writeFile(
filePath,
strict
? generateValidatorFileStrict(manifest)
: generateValidatorFile(manifest)
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -1179,7 +1179,11 @@ async function startWatcher(
routeTypesFilePath,
opts.nextConfig
)
await writeValidatorFile(routeTypesManifest, validatorFilePath)
await writeValidatorFile(
routeTypesManifest,
validatorFilePath,
Boolean(nextConfig.experimental.strictRouteTypes)
)

// Generate cache-life types if cacheLife config exists
const cacheLifeFilePath = path.join(distTypesDir, 'cache-life.d.ts')
Expand Down
Loading
Loading