Skip to content

Commit 6344c90

Browse files
committed
Turbopack: support config.turbopack and deprecate config.experimental.turbopack.
This: - Adds support for using `config.turbopack` for Turbopack. The accepted value for this option is identical to the previous experimental one without the deprecated field `loaders`. - Deprecates `config.experimental.turbo`. Warns on its use, but will continue to accept it, merging it with `config.turbopack` while preferring fields on `config.turbopack`. Test Plan: - [ ] Convert use of `config.experimental.turbo` in tests to `config.turbopack` - [ ] Automated test for accepting the experimental option for compatibility, as well as the config merging
1 parent de09677 commit 6344c90

File tree

7 files changed

+144
-106
lines changed

7 files changed

+144
-106
lines changed

Diff for: crates/next-core/src/next_config.rs

+11-31
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ pub struct NextConfig {
9494
pub cross_origin: Option<CrossOriginConfig>,
9595
pub dev_indicators: Option<DevIndicatorsConfig>,
9696
pub output: Option<OutputType>,
97+
pub turbopack: Option<TurbopackConfig>,
9798

9899
/// Enables the bundling of node_modules packages (externals) for pages
99100
/// server-side bundles.
@@ -536,7 +537,7 @@ pub enum RemotePatternProtocal {
536537
OperationValue,
537538
)]
538539
#[serde(rename_all = "camelCase")]
539-
pub struct ExperimentalTurboConfig {
540+
pub struct TurbopackConfig {
540541
/// This option has been replaced by `rules`.
541542
pub loaders: Option<JsonValue>,
542543
pub rules: Option<FxIndexMap<RcStr, RuleConfigItemOrShortcut>>,
@@ -668,7 +669,6 @@ pub struct ExperimentalConfig {
668669
mdx_rs: Option<MdxRsOptions>,
669670
strict_next_head: Option<bool>,
670671
swc_plugins: Option<Vec<(RcStr, serde_json::Value)>>,
671-
turbo: Option<ExperimentalTurboConfig>,
672672
external_middleware_rewrites_resolve: Option<bool>,
673673
scroll_restoration: Option<bool>,
674674
manual_client_base_path: Option<bool>,
@@ -1144,12 +1144,7 @@ impl NextConfig {
11441144

11451145
#[turbo_tasks::function]
11461146
pub fn webpack_rules(&self, active_conditions: Vec<RcStr>) -> Vc<OptionWebpackRules> {
1147-
let Some(turbo_rules) = self
1148-
.experimental
1149-
.turbo
1150-
.as_ref()
1151-
.and_then(|t| t.rules.as_ref())
1152-
else {
1147+
let Some(turbo_rules) = self.turbopack.as_ref().and_then(|t| t.rules.as_ref()) else {
11531148
return Vc::cell(None);
11541149
};
11551150
if turbo_rules.is_empty() {
@@ -1233,8 +1228,7 @@ impl NextConfig {
12331228
#[turbo_tasks::function]
12341229
pub fn persistent_caching_enabled(&self) -> Result<Vc<bool>> {
12351230
Ok(Vc::cell(
1236-
self.experimental
1237-
.turbo
1231+
self.turbopack
12381232
.as_ref()
12391233
.and_then(|t| t.unstable_persistent_caching)
12401234
.unwrap_or_default(),
@@ -1244,8 +1238,7 @@ impl NextConfig {
12441238
#[turbo_tasks::function]
12451239
pub fn resolve_alias_options(&self) -> Result<Vc<ResolveAliasMap>> {
12461240
let Some(resolve_alias) = self
1247-
.experimental
1248-
.turbo
1241+
.turbopack
12491242
.as_ref()
12501243
.and_then(|t| t.resolve_alias.as_ref())
12511244
else {
@@ -1258,8 +1251,7 @@ impl NextConfig {
12581251
#[turbo_tasks::function]
12591252
pub fn resolve_extension(&self) -> Vc<ResolveExtensions> {
12601253
let Some(resolve_extensions) = self
1261-
.experimental
1262-
.turbo
1254+
.turbopack
12631255
.as_ref()
12641256
.and_then(|t| t.resolve_extensions.as_ref())
12651257
else {
@@ -1476,11 +1468,7 @@ impl NextConfig {
14761468
&self,
14771469
_is_development: bool,
14781470
) -> Vc<OptionTreeShaking> {
1479-
let tree_shaking = self
1480-
.experimental
1481-
.turbo
1482-
.as_ref()
1483-
.and_then(|v| v.tree_shaking);
1471+
let tree_shaking = self.turbopack.as_ref().and_then(|v| v.tree_shaking);
14841472

14851473
OptionTreeShaking(match tree_shaking {
14861474
Some(false) => Some(TreeShakingMode::ReexportsOnly),
@@ -1492,11 +1480,7 @@ impl NextConfig {
14921480

14931481
#[turbo_tasks::function]
14941482
pub fn tree_shaking_mode_for_user_code(&self, _is_development: bool) -> Vc<OptionTreeShaking> {
1495-
let tree_shaking = self
1496-
.experimental
1497-
.turbo
1498-
.as_ref()
1499-
.and_then(|v| v.tree_shaking);
1483+
let tree_shaking = self.turbopack.as_ref().and_then(|v| v.tree_shaking);
15001484

15011485
OptionTreeShaking(match tree_shaking {
15021486
Some(false) => Some(TreeShakingMode::ReexportsOnly),
@@ -1508,11 +1492,7 @@ impl NextConfig {
15081492

15091493
#[turbo_tasks::function]
15101494
pub fn module_id_strategy_config(&self) -> Vc<OptionModuleIdStrategy> {
1511-
let Some(module_id_strategy) = self
1512-
.experimental
1513-
.turbo
1514-
.as_ref()
1515-
.and_then(|t| t.module_id_strategy)
1495+
let Some(module_id_strategy) = self.turbopack.as_ref().and_then(|t| t.module_id_strategy)
15161496
else {
15171497
return Vc::cell(None);
15181498
};
@@ -1521,7 +1501,7 @@ impl NextConfig {
15211501

15221502
#[turbo_tasks::function]
15231503
pub async fn turbo_minify(&self, mode: Vc<NextMode>) -> Result<Vc<bool>> {
1524-
let minify = self.experimental.turbo.as_ref().and_then(|t| t.minify);
1504+
let minify = self.turbopack.as_ref().and_then(|t| t.minify);
15251505

15261506
Ok(Vc::cell(
15271507
minify.unwrap_or(matches!(*mode.await?, NextMode::Build)),
@@ -1530,7 +1510,7 @@ impl NextConfig {
15301510

15311511
#[turbo_tasks::function]
15321512
pub async fn turbo_source_maps(&self) -> Result<Vc<bool>> {
1533-
let source_maps = self.experimental.turbo.as_ref().and_then(|t| t.source_maps);
1513+
let source_maps = self.turbopack.as_ref().and_then(|t| t.source_maps);
15341514

15351515
Ok(Vc::cell(source_maps.unwrap_or(true)))
15361516
}

Diff for: examples/basic-css/tsconfig.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@
1818
"name": "next"
1919
}
2020
],
21-
"strictNullChecks": true
21+
"strictNullChecks": true,
22+
"target": "ES2017"
2223
},
2324
"include": ["next-env.d.ts", ".next/types/**/*.ts", "**/*.ts", "**/*.tsx"],
24-
"exclude": ["node_modules"]
25+
"exclude": ["node_modules", "**/*.test.ts", "**/*.test.tsx"]
2526
}

Diff for: examples/with-redux/tsconfig.json

+9-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
"$schema": "https://json.schemastore.org/tsconfig",
33
"compilerOptions": {
44
"baseUrl": ".",
5-
"paths": { "@/*": ["./*"] },
5+
"paths": {
6+
"@/*": ["./*"]
7+
},
68
"target": "ESNext",
79
"lib": ["DOM", "DOM.Iterable", "ESNext"],
810
"allowJs": true,
@@ -17,8 +19,12 @@
1719
"isolatedModules": true,
1820
"jsx": "preserve",
1921
"incremental": true,
20-
"plugins": [{ "name": "next" }]
22+
"plugins": [
23+
{
24+
"name": "next"
25+
}
26+
]
2127
},
2228
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
23-
"exclude": ["node_modules"]
29+
"exclude": ["node_modules", "**/*.test.ts", "**/*.test.tsx"]
2430
}

Diff for: packages/next/src/build/swc/index.ts

+11-8
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ import { patchIncorrectLockfile } from '../../lib/patch-incorrect-lockfile'
1010
import { downloadNativeNextSwc, downloadWasmSwc } from '../../lib/download-swc'
1111
import type {
1212
NextConfigComplete,
13-
TurboLoaderItem,
14-
TurboRuleConfigItem,
15-
TurboRuleConfigItemOptions,
16-
TurboRuleConfigItemOrShortcut,
13+
TurbopackLoaderItem,
14+
TurbopackRuleConfigItem,
15+
TurbopackRuleConfigItemOptions,
16+
TurbopackRuleConfigItemOrShortcut,
1717
} from '../../server/config-shared'
1818
import { isDeepStrictEqual } from 'util'
1919
import {
@@ -878,7 +878,7 @@ function bindingToApi(
878878
}
879879

880880
function ensureLoadersHaveSerializableOptions(
881-
turbopackRules: Record<string, TurboRuleConfigItemOrShortcut>
881+
turbopackRules: Record<string, TurbopackRuleConfigItemOrShortcut>
882882
) {
883883
for (const [glob, rule] of Object.entries(turbopackRules)) {
884884
if (Array.isArray(rule)) {
@@ -888,10 +888,10 @@ function bindingToApi(
888888
}
889889
}
890890

891-
function checkConfigItem(rule: TurboRuleConfigItem, glob: string) {
891+
function checkConfigItem(rule: TurbopackRuleConfigItem, glob: string) {
892892
if (!rule) return
893893
if ('loaders' in rule) {
894-
checkLoaderItems((rule as TurboRuleConfigItemOptions).loaders, glob)
894+
checkLoaderItems((rule as TurbopackRuleConfigItemOptions).loaders, glob)
895895
} else {
896896
for (const key in rule) {
897897
const inner = rule[key]
@@ -902,7 +902,10 @@ function bindingToApi(
902902
}
903903
}
904904

905-
function checkLoaderItems(loaderItems: TurboLoaderItem[], glob: string) {
905+
function checkLoaderItems(
906+
loaderItems: TurbopackLoaderItem[],
907+
glob: string
908+
) {
906909
for (const loaderItem of loaderItems) {
907910
if (
908911
typeof loaderItem !== 'string' &&

Diff for: packages/next/src/server/config-schema.ts

+61-39
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@ import type zod from 'next/dist/compiled/zod'
77
import type { SizeLimit } from '../types'
88
import type {
99
ExportPathMap,
10-
TurboLoaderItem,
11-
TurboRuleConfigItem,
12-
TurboRuleConfigItemOptions,
13-
TurboRuleConfigItemOrShortcut,
10+
TurbopackLoaderItem,
11+
DeprecatedExperimentalTurboOptions,
12+
TurbopackOptions,
13+
TurbopackRuleConfigItem,
14+
TurbopackRuleConfigItemOptions,
15+
TurbopackRuleConfigItemOrShortcut,
1416
} from './config-shared'
1517
import type {
1618
Header,
@@ -99,7 +101,7 @@ const zHeader: zod.ZodType<Header> = z.object({
99101
internal: z.boolean().optional(),
100102
})
101103

102-
const zTurboLoaderItem: zod.ZodType<TurboLoaderItem> = z.union([
104+
const zTurboLoaderItem: zod.ZodType<TurbopackLoaderItem> = z.union([
103105
z.string(),
104106
z.object({
105107
loader: z.string(),
@@ -108,24 +110,69 @@ const zTurboLoaderItem: zod.ZodType<TurboLoaderItem> = z.union([
108110
}),
109111
])
110112

111-
const zTurboRuleConfigItemOptions: zod.ZodType<TurboRuleConfigItemOptions> =
113+
const zTurboRuleConfigItemOptions: zod.ZodType<TurbopackRuleConfigItemOptions> =
112114
z.object({
113115
loaders: z.array(zTurboLoaderItem),
114116
as: z.string().optional(),
115117
})
116118

117-
const zTurboRuleConfigItem: zod.ZodType<TurboRuleConfigItem> = z.union([
119+
const zTurboRuleConfigItem: zod.ZodType<TurbopackRuleConfigItem> = z.union([
118120
z.literal(false),
119121
z.record(
120122
z.string(),
121123
z.lazy(() => zTurboRuleConfigItem)
122124
),
123125
zTurboRuleConfigItemOptions,
124126
])
125-
126-
const zTurboRuleConfigItemOrShortcut: zod.ZodType<TurboRuleConfigItemOrShortcut> =
127+
const zTurboRuleConfigItemOrShortcut: zod.ZodType<TurbopackRuleConfigItemOrShortcut> =
127128
z.union([z.array(zTurboLoaderItem), zTurboRuleConfigItem])
128129

130+
const zTurbopackConfig: zod.ZodType<TurbopackOptions> = z.object({
131+
rules: z.record(z.string(), zTurboRuleConfigItemOrShortcut).optional(),
132+
resolveAlias: z
133+
.record(
134+
z.string(),
135+
z.union([
136+
z.string(),
137+
z.array(z.string()),
138+
z.record(z.string(), z.union([z.string(), z.array(z.string())])),
139+
])
140+
)
141+
.optional(),
142+
resolveExtensions: z.array(z.string()).optional(),
143+
treeShaking: z.boolean().optional(),
144+
persistentCaching: z.union([z.number(), z.literal(false)]).optional(),
145+
memoryLimit: z.number().optional(),
146+
moduleIdStrategy: z.enum(['named', 'deterministic']).optional(),
147+
minify: z.boolean().optional(),
148+
sourceMaps: z.boolean().optional(),
149+
})
150+
151+
// Same as zTurbopackConfig but with deprecated properties. Unfortunately, base
152+
// properties are duplicated here as `ZodType`s do not export `extend()`.
153+
const zDeprecatedExperimentalTurboConfig: zod.ZodType<DeprecatedExperimentalTurboOptions> =
154+
z.object({
155+
loaders: z.record(z.string(), z.array(zTurboLoaderItem)).optional(),
156+
rules: z.record(z.string(), zTurboRuleConfigItemOrShortcut).optional(),
157+
resolveAlias: z
158+
.record(
159+
z.string(),
160+
z.union([
161+
z.string(),
162+
z.array(z.string()),
163+
z.record(z.string(), z.union([z.string(), z.array(z.string())])),
164+
])
165+
)
166+
.optional(),
167+
resolveExtensions: z.array(z.string()).optional(),
168+
treeShaking: z.boolean().optional(),
169+
persistentCaching: z.union([z.number(), z.literal(false)]).optional(),
170+
memoryLimit: z.number().optional(),
171+
moduleIdStrategy: z.enum(['named', 'deterministic']).optional(),
172+
minify: z.boolean().optional(),
173+
sourceMaps: z.boolean().optional(),
174+
})
175+
129176
export const configSchema: zod.ZodType<NextConfig> = z.lazy(() =>
130177
z.strictObject({
131178
allowedDevOrigins: z.array(z.string()).optional(),
@@ -391,36 +438,10 @@ export const configSchema: zod.ZodType<NextConfig> = z.lazy(() =>
391438
typedRoutes: z.boolean().optional(),
392439
webpackBuildWorker: z.boolean().optional(),
393440
webpackMemoryOptimizations: z.boolean().optional(),
394-
turbo: z
395-
.object({
396-
loaders: z.record(z.string(), z.array(zTurboLoaderItem)).optional(),
397-
rules: z
398-
.record(z.string(), zTurboRuleConfigItemOrShortcut)
399-
.optional(),
400-
resolveAlias: z
401-
.record(
402-
z.string(),
403-
z.union([
404-
z.string(),
405-
z.array(z.string()),
406-
z.record(
407-
z.string(),
408-
z.union([z.string(), z.array(z.string())])
409-
),
410-
])
411-
)
412-
.optional(),
413-
resolveExtensions: z.array(z.string()).optional(),
414-
treeShaking: z.boolean().optional(),
415-
persistentCaching: z
416-
.union([z.number(), z.literal(false)])
417-
.optional(),
418-
memoryLimit: z.number().optional(),
419-
moduleIdStrategy: z.enum(['named', 'deterministic']).optional(),
420-
minify: z.boolean().optional(),
421-
sourceMaps: z.boolean().optional(),
422-
})
423-
.optional(),
441+
/**
442+
* @deprecated Use `config.turbopack` instead.
443+
*/
444+
turbo: zDeprecatedExperimentalTurboConfig.optional(),
424445
optimizePackageImports: z.array(z.string()).optional(),
425446
optimizeServerReact: z.boolean().optional(),
426447
clientTraceMetadata: z.array(z.string()).optional(),
@@ -657,6 +678,7 @@ export const configSchema: zod.ZodType<NextConfig> = z.lazy(() =>
657678
target: z.string().optional(),
658679
trailingSlash: z.boolean().optional(),
659680
transpilePackages: z.array(z.string()).optional(),
681+
turbopack: zTurbopackConfig.optional(),
660682
typescript: z
661683
.strictObject({
662684
ignoreBuildErrors: z.boolean().optional(),

0 commit comments

Comments
 (0)