From 05d428b83d621aa99c08c943aca1163e09d3702e Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Fri, 25 Aug 2023 16:34:59 -0700 Subject: [PATCH 1/2] Update examples and schema for Turbopack loaders config change This addresses inconsistencies with existing examples and config schema from changes in #49535. --- .../05-next-config-js/turbo.mdx | 6 +++--- .../with-turbopack-loaders/next.config.js | 11 +++++++++-- examples/with-turbopack-loaders/package.json | 2 ++ .../with-turbopack-loaders/pages/index.js | 3 ++- examples/with-turbopack-loaders/styles.styl | 2 ++ .../{vercel.svg => vercel.react.svg} | 0 packages/next/src/build/swc/index.ts | 19 +++++++++++-------- packages/next/src/server/config-schema.ts | 2 +- packages/next/src/server/config-shared.ts | 9 ++++++++- 9 files changed, 38 insertions(+), 16 deletions(-) create mode 100644 examples/with-turbopack-loaders/styles.styl rename examples/with-turbopack-loaders/{vercel.svg => vercel.react.svg} (100%) diff --git a/docs/02-app/02-api-reference/05-next-config-js/turbo.mdx b/docs/02-app/02-api-reference/05-next-config-js/turbo.mdx index 09c3044d26b90..d752e14cbbdfb 100644 --- a/docs/02-app/02-api-reference/05-next-config-js/turbo.mdx +++ b/docs/02-app/02-api-reference/05-next-config-js/turbo.mdx @@ -18,9 +18,9 @@ To configure loaders, add the names of the loaders you've installed and any opti module.exports = { experimental: { turbo: { - loaders: { + rules: { // Option format - '.md': [ + '*.md': [ { loader: '@mdx-js/loader', options: { @@ -29,7 +29,7 @@ module.exports = { }, ], // Option-less format - '.mdx': ['@mdx-js/loader'], + '*.mdx': ['@mdx-js/loader'], }, }, }, diff --git a/examples/with-turbopack-loaders/next.config.js b/examples/with-turbopack-loaders/next.config.js index 4b89c10aa7529..5ba0898344f7c 100644 --- a/examples/with-turbopack-loaders/next.config.js +++ b/examples/with-turbopack-loaders/next.config.js @@ -1,8 +1,15 @@ module.exports = { experimental: { turbo: { - loaders: { - '.svg': ['@svgr/webpack'], + rules: { + '*.react.svg': { + loaders: ['@svgr/webpack'], + as: '*.js', + }, + '*.styl': { + loaders: ['stylus-loader'], + as: '*.css', + }, }, }, }, diff --git a/examples/with-turbopack-loaders/package.json b/examples/with-turbopack-loaders/package.json index c70cb28065381..f0590fa8ad5af 100644 --- a/examples/with-turbopack-loaders/package.json +++ b/examples/with-turbopack-loaders/package.json @@ -15,6 +15,8 @@ "@types/node": "^18.11.9", "@types/react": "^18.0.25", "@types/react-dom": "^18.0.9", + "stylus": "0.59.0", + "stylus-loader": "7.1.3", "typescript": "^4.9.3" } } diff --git a/examples/with-turbopack-loaders/pages/index.js b/examples/with-turbopack-loaders/pages/index.js index 574261858ff39..cf2f400b782ae 100644 --- a/examples/with-turbopack-loaders/pages/index.js +++ b/examples/with-turbopack-loaders/pages/index.js @@ -1,4 +1,5 @@ -import Vercel from '../vercel.svg' +import Vercel from '../vercel.react.svg' +import '../styles.styl' export default function Home() { return diff --git a/examples/with-turbopack-loaders/styles.styl b/examples/with-turbopack-loaders/styles.styl new file mode 100644 index 0000000000000..9e8b98a7a5f09 --- /dev/null +++ b/examples/with-turbopack-loaders/styles.styl @@ -0,0 +1,2 @@ +body + background-color: blue diff --git a/examples/with-turbopack-loaders/vercel.svg b/examples/with-turbopack-loaders/vercel.react.svg similarity index 100% rename from examples/with-turbopack-loaders/vercel.svg rename to examples/with-turbopack-loaders/vercel.react.svg diff --git a/packages/next/src/build/swc/index.ts b/packages/next/src/build/swc/index.ts index b4c64f853d545..4977f89767b4b 100644 --- a/packages/next/src/build/swc/index.ts +++ b/packages/next/src/build/swc/index.ts @@ -9,7 +9,11 @@ import { eventSwcLoadFailure } from '../../telemetry/events/swc-load-failure' import { patchIncorrectLockfile } from '../../lib/patch-incorrect-lockfile' import { downloadWasmSwc, downloadNativeNextSwc } from '../../lib/download-swc' import { spawn } from 'child_process' -import { NextConfigComplete, TurboLoaderItem } from '../../server/config-shared' +import { + NextConfigComplete, + TurboLoaderItem, + TurboRule, +} from '../../server/config-shared' import { isDeepStrictEqual } from 'util' const nextVersion = process.env.__NEXT_VERSION as string @@ -963,10 +967,8 @@ function bindingToApi(binding: any, _wasm: boolean) { nextConfigSerializable.exportPathMap = {} nextConfigSerializable.webpack = nextConfig.webpack && {} - if (nextConfig.experimental?.turbo?.loaders) { - ensureLoadersHaveSerializableOptions( - nextConfig.experimental.turbo.loaders - ) + if (nextConfig.experimental?.turbo?.rules) { + ensureLoadersHaveSerializableOptions(nextConfig.experimental.turbo?.rules) } nextConfigSerializable.modularizeImports = @@ -994,16 +996,17 @@ function bindingToApi(binding: any, _wasm: boolean) { } function ensureLoadersHaveSerializableOptions( - turbopackLoaders: Record + turbopackRules: Record ) { - for (const [ext, loaderItems] of Object.entries(turbopackLoaders)) { + for (const [glob, rule] of Object.entries(turbopackRules)) { + const loaderItems = Array.isArray(rule) ? rule : rule.loaders for (const loaderItem of loaderItems) { if ( typeof loaderItem !== 'string' && !isDeepStrictEqual(loaderItem, JSON.parse(JSON.stringify(loaderItem))) ) { throw new Error( - `loader ${loaderItem.loader} for match "${ext}" does not have serializable options. Ensure that options passed are plain JavaScript objects and values.` + `loader ${loaderItem.loader} for match "${glob}" does not have serializable options. Ensure that options passed are plain JavaScript objects and values.` ) } } diff --git a/packages/next/src/server/config-schema.ts b/packages/next/src/server/config-schema.ts index b2f974bc69c2d..366850391e6f5 100644 --- a/packages/next/src/server/config-schema.ts +++ b/packages/next/src/server/config-schema.ts @@ -465,7 +465,7 @@ const configSchema = { type: 'object', additionalProperties: false, properties: { - loaders: { + rules: { type: 'object', }, resolveAlias: { diff --git a/packages/next/src/server/config-shared.ts b/packages/next/src/server/config-shared.ts index a9e34c7c0b6c6..0c45a60402c6a 100644 --- a/packages/next/src/server/config-shared.ts +++ b/packages/next/src/server/config-shared.ts @@ -93,6 +93,13 @@ export type TurboLoaderItem = options: Record } +export type TurboRule = + | TurboLoaderItem[] + | { + loaders: TurboLoaderItem[] + as: string + } + export interface ExperimentalTurboOptions { /** * (`next --turbo` only) A mapping of aliased imports to modules to load in their place. @@ -109,7 +116,7 @@ export interface ExperimentalTurboOptions { * * @see [Turbopack Loaders](https://nextjs.org/docs/app/api-reference/next-config-js/turbo#webpack-loaders) */ - loaders?: Record + rules?: Record } export interface WebpackConfigContext { From 2022b867d9fdf68d04ca8e506327dfa0bb244636 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Wed, 6 Sep 2023 17:38:58 -0700 Subject: [PATCH 2/2] fixup! Merge remote-tracking branch 'origin/canary' into wbinnssmith/rules --- .../crates/next-core/src/next_config.rs | 2 +- packages/next/src/server/config-schema.ts | 3 +++ packages/next/src/server/config-shared.ts | 7 ++++++ packages/next/src/server/config.ts | 22 +++++++++++++++++++ 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-core/src/next_config.rs b/packages/next-swc/crates/next-core/src/next_config.rs index c4e90cca6908d..55a7d693f88c0 100644 --- a/packages/next-swc/crates/next-core/src/next_config.rs +++ b/packages/next-swc/crates/next-core/src/next_config.rs @@ -376,7 +376,7 @@ pub enum RemotePatternProtocal { #[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, TraceRawVcs)] #[serde(rename_all = "camelCase")] pub struct ExperimentalTurboConfig { - /// This option has been replace by `rules`. + /// This option has been replaced by `rules`. pub loaders: Option, pub rules: Option>, pub resolve_alias: Option>, diff --git a/packages/next/src/server/config-schema.ts b/packages/next/src/server/config-schema.ts index 6a138cfc23287..188803bf9bed6 100644 --- a/packages/next/src/server/config-schema.ts +++ b/packages/next/src/server/config-schema.ts @@ -450,6 +450,9 @@ const configSchema = { type: 'object', additionalProperties: false, properties: { + loaders: { + type: 'object', + }, rules: { type: 'object', }, diff --git a/packages/next/src/server/config-shared.ts b/packages/next/src/server/config-shared.ts index 53bc6352acb65..db382866f2efb 100644 --- a/packages/next/src/server/config-shared.ts +++ b/packages/next/src/server/config-shared.ts @@ -111,6 +111,13 @@ export interface ExperimentalTurboOptions { string | string[] | Record > + /** + * (`next --turbo` only) A list of webpack loaders to apply when running with Turbopack. + * + * @see [Turbopack Loaders](https://nextjs.org/docs/app/api-reference/next-config-js/turbo#webpack-loaders) + */ + loaders?: Record + /** * (`next --turbo` only) A list of webpack loaders to apply when running with Turbopack. * diff --git a/packages/next/src/server/config.ts b/packages/next/src/server/config.ts index 64eb5985699a2..5799c92085441 100644 --- a/packages/next/src/server/config.ts +++ b/packages/next/src/server/config.ts @@ -12,6 +12,7 @@ import { NextConfigComplete, validateConfig, NextConfig, + TurboLoaderItem, } from './config-shared' import { loadWebpackHook } from './config-utils' import { ImageConfig, imageConfigDefault } from '../shared/lib/image-config' @@ -849,6 +850,27 @@ export default async function loadConfig( : canonicalBase) || '' } + if ( + userConfig.experimental?.turbo?.loaders && + !userConfig.experimental?.turbo?.rules + ) { + curLog.warn( + 'experimental.turbo.loaders is now deprecated. Please update next.config.js to use experimental.turbo.rules as soon as possible.\n' + + 'The new option is similar, but the key should be a glob instead of an extension.\n' + + 'Example: loaders: { ".mdx": ["mdx-loader"] } -> rules: { "*.mdx": ["mdx-loader"] }" }\n' + + 'See more info here https://nextjs.org/docs/app/api-reference/next-config-js/turbo' + ) + + const rules: Record = {} + for (const [ext, loaders] of Object.entries( + userConfig.experimental.turbo.loaders + )) { + rules['*' + ext] = loaders as TurboLoaderItem[] + } + + userConfig.experimental.turbo.rules = rules + } + onLoadUserConfig?.(userConfig) const completeConfig = assignDefaults( dir,