Skip to content

Commit

Permalink
Allow silencing direct access of dynamic APIs to unblock internal sync (
Browse files Browse the repository at this point in the history
  • Loading branch information
eps1lon authored Oct 2, 2024
1 parent b95f012 commit accec7b
Show file tree
Hide file tree
Showing 9 changed files with 205 additions and 134 deletions.
4 changes: 4 additions & 0 deletions packages/next/src/build/webpack/plugins/define-env-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,10 @@ export function getDefineEnv({
'process.env.__NEXT_LINK_NO_TOUCH_START':
config.experimental.linkNoTouchStart ?? false,
'process.env.__NEXT_ASSET_PREFIX': config.assetPrefix,
'process.env.__NEXT_DISABLE_SYNC_DYNAMIC_API_WARNINGS':
// Internal only so untyped to avoid discovery
(config.experimental as any).internal_disableSyncDynamicAPIWarnings ??
false,
...(isNodeOrEdgeCompilation
? {
// Fix bad-actors in the npm ecosystem (e.g. `node-formidable`)
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 @@ -303,6 +303,7 @@ export const configSchema: zod.ZodType<NextConfig> = z.lazy(() =>
forceSwcTransforms: z.boolean().optional(),
fullySpecified: z.boolean().optional(),
gzipSize: z.boolean().optional(),
internal_disableSyncDynamicAPIWarnings: z.boolean().optional(),
isrFlushToDisk: z.boolean().optional(),
largePageDataBytes: z.number().optional(),
linkNoTouchStart: z.boolean().optional(),
Expand Down
39 changes: 23 additions & 16 deletions packages/next/src/server/request/cookies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -510,23 +510,30 @@ function describeNameArg(arg: unknown) {
: '...'
}

function warnForSyncIteration(route?: string) {
const prefix = route ? ` In route ${route} ` : ''
console.error(
`${prefix}cookies were iterated over. ` +
`\`cookies()\` should be awaited before using its value. ` +
`Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis`
)
}
const noop = () => {}

function warnForSyncAccess(route: undefined | string, expression: string) {
const prefix = route ? ` In route ${route} a ` : 'A '
console.error(
`${prefix}cookie property was accessed directly with \`${expression}\`. ` +
`\`cookies()\` should be awaited before using its value. ` +
`Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis`
)
}
const warnForSyncIteration = process.env
.__NEXT_DISABLE_SYNC_DYNAMIC_API_WARNINGS
? noop
: function warnForSyncIteration(route?: string) {
const prefix = route ? ` In route ${route} ` : ''
console.error(
`${prefix}cookies were iterated over. ` +
`\`cookies()\` should be awaited before using its value. ` +
`Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis`
)
}

const warnForSyncAccess = process.env.__NEXT_DISABLE_SYNC_DYNAMIC_API_WARNINGS
? noop
: function warnForSyncAccess(route: undefined | string, expression: string) {
const prefix = route ? ` In route ${route} a ` : 'A '
console.error(
`${prefix}cookie property was accessed directly with \`${expression}\`. ` +
`\`cookies()\` should be awaited before using its value. ` +
`Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis`
)
}

function polyfilledResponseCookiesIterator(
this: ResponseCookies
Expand Down
20 changes: 12 additions & 8 deletions packages/next/src/server/request/draft-mode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,11 +163,15 @@ class DraftMode {
}
}

function warnForSyncAccess(route: undefined | string, expression: string) {
const prefix = route ? ` In route ${route} a ` : 'A '
console.error(
`${prefix}\`draftMode()\` property was accessed directly with \`${expression}\`. ` +
`\`draftMode()\` should be awaited before using its value. ` +
`Learn more: https://nextjs.org/docs/messages/draft-mode-sync-access`
)
}
const noop = () => {}

const warnForSyncAccess = process.env.__NEXT_DISABLE_SYNC_DYNAMIC_API_WARNINGS
? noop
: function warnForSyncAccess(route: undefined | string, expression: string) {
const prefix = route ? ` In route ${route} a ` : 'A '
console.error(
`${prefix}\`draftMode()\` property was accessed directly with \`${expression}\`. ` +
`\`draftMode()\` should be awaited before using its value. ` +
`Learn more: https://nextjs.org/docs/messages/draft-mode-sync-access`
)
}
39 changes: 23 additions & 16 deletions packages/next/src/server/request/headers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -425,23 +425,30 @@ function describeNameArg(arg: unknown) {
return typeof arg === 'string' ? `'${arg}'` : '...'
}

function warnForSyncIteration(route?: string) {
const prefix = route ? ` In route ${route} ` : ''
console.error(
`${prefix}headers were iterated over. ` +
`\`headers()\` should be awaited before using its value. ` +
`Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis`
)
}
const noop = () => {}

function warnForSyncAccess(route: undefined | string, expression: string) {
const prefix = route ? ` In route ${route} a ` : 'A '
console.error(
`${prefix}header property was accessed directly with \`${expression}\`. ` +
`\`headers()\` should be awaited before using its value. ` +
`Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis`
)
}
const warnForSyncIteration = process.env
.__NEXT_DISABLE_SYNC_DYNAMIC_API_WARNINGS
? noop
: function warnForSyncIteration(route?: string) {
const prefix = route ? ` In route ${route} ` : ''
console.error(
`${prefix}headers were iterated over. ` +
`\`headers()\` should be awaited before using its value. ` +
`Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis`
)
}

const warnForSyncAccess = process.env.__NEXT_DISABLE_SYNC_DYNAMIC_API_WARNINGS
? noop
: function warnForSyncAccess(route: undefined | string, expression: string) {
const prefix = route ? ` In route ${route} a ` : 'A '
console.error(
`${prefix}header property was accessed directly with \`${expression}\`. ` +
`\`headers()\` should be awaited before using its value. ` +
`Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis`
)
}

type HeadersExtensions = {
[K in keyof ReadonlyHeaders]: unknown
Expand Down
58 changes: 36 additions & 22 deletions packages/next/src/server/request/params.browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,29 +119,43 @@ function makeDynamicallyTrackedExoticParamsWithDevWarnings(
return proxiedPromise
}

function warnForSyncAccess(expression: string) {
console.error(
`A param property was accessed directly with ${expression}. \`params\` is now a Promise and should be unwrapped with \`React.use()\` before accessing properties of the underlying params object. In this version of Next.js direct access to param properties is still supported to facilitate migration but in a future version you will be required to unwrap \`params\` with \`React.use()\`.`
)
}
const noop = () => {}

function warnForEnumeration(missingProperties: Array<string>) {
if (missingProperties.length) {
const describedMissingProperties =
describeListOfPropertyNames(missingProperties)
console.error(
`params are being enumerated incompletely missing these properties: ${describedMissingProperties}. ` +
`\`params\` should be unwrapped with \`React.use()\` before using its value. ` +
`Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis`
)
} else {
console.error(
`params are being enumerated. ` +
`\`params\` should be unwrapped with \`React.use()\` before using its value. ` +
`Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis`
)
}
}
const warnForSyncAccess = process.env.__NEXT_DISABLE_SYNC_DYNAMIC_API_WARNINGS
? noop
: function warnForSyncAccess(expression: string) {
if (process.env.__NEXT_DISABLE_SYNC_DYNAMIC_API_WARNINGS) {
return
}

console.error(
`A param property was accessed directly with ${expression}. \`params\` is now a Promise and should be unwrapped with \`React.use()\` before accessing properties of the underlying params object. In this version of Next.js direct access to param properties is still supported to facilitate migration but in a future version you will be required to unwrap \`params\` with \`React.use()\`.`
)
}

const warnForEnumeration = process.env.__NEXT_DISABLE_SYNC_DYNAMIC_API_WARNINGS
? noop
: function warnForEnumeration(missingProperties: Array<string>) {
if (process.env.__NEXT_DISABLE_SYNC_DYNAMIC_API_WARNINGS) {
return
}

if (missingProperties.length) {
const describedMissingProperties =
describeListOfPropertyNames(missingProperties)
console.error(
`params are being enumerated incompletely missing these properties: ${describedMissingProperties}. ` +
`\`params\` should be unwrapped with \`React.use()\` before using its value. ` +
`Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis`
)
} else {
console.error(
`params are being enumerated. ` +
`\`params\` should be unwrapped with \`React.use()\` before using its value. ` +
`Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis`
)
}
}

function describeListOfPropertyNames(properties: Array<string>) {
switch (properties.length) {
Expand Down
72 changes: 43 additions & 29 deletions packages/next/src/server/request/params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -495,36 +495,50 @@ function makeDynamicallyTrackedExoticParamsWithDevWarnings(
return proxiedPromise
}

function warnForSyncAccess(route: undefined | string, expression: string) {
const prefix = route ? ` In route ${route} a ` : 'A '
console.error(
`${prefix}param property was accessed directly with ${expression}. ` +
`\`params\` should be awaited before accessing its properties. ` +
`Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis`
)
}
const noop = () => {}

function warnForEnumeration(
route: undefined | string,
missingProperties: Array<string>
) {
const prefix = route ? ` In route ${route} ` : ''
if (missingProperties.length) {
const describedMissingProperties =
describeListOfPropertyNames(missingProperties)
console.error(
`${prefix}params are being enumerated incompletely missing these properties: ${describedMissingProperties}. ` +
`\`params\` should be awaited before accessing its properties. ` +
`Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis`
)
} else {
console.error(
`${prefix}params are being enumerated. ` +
`\`params\` should be awaited before accessing its properties. ` +
`Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis`
)
}
}
const warnForSyncAccess = process.env.__NEXT_DISABLE_SYNC_DYNAMIC_API_WARNINGS
? noop
: function warnForSyncAccess(route: undefined | string, expression: string) {
if (process.env.__NEXT_DISABLE_SYNC_DYNAMIC_API_WARNINGS) {
return
}

const prefix = route ? ` In route ${route} a ` : 'A '
console.error(
`${prefix}param property was accessed directly with ${expression}. ` +
`\`params\` should be awaited before accessing its properties. ` +
`Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis`
)
}

const warnForEnumeration = process.env.__NEXT_DISABLE_SYNC_DYNAMIC_API_WARNINGS
? noop
: function warnForEnumeration(
route: undefined | string,
missingProperties: Array<string>
) {
if (process.env.__NEXT_DISABLE_SYNC_DYNAMIC_API_WARNINGS) {
return
}

const prefix = route ? ` In route ${route} ` : ''
if (missingProperties.length) {
const describedMissingProperties =
describeListOfPropertyNames(missingProperties)
console.error(
`${prefix}params are being enumerated incompletely missing these properties: ${describedMissingProperties}. ` +
`\`params\` should be awaited before accessing its properties. ` +
`Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis`
)
} else {
console.error(
`${prefix}params are being enumerated. ` +
`\`params\` should be awaited before accessing its properties. ` +
`Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis`
)
}
}

function describeListOfPropertyNames(properties: Array<string>) {
switch (properties.length) {
Expand Down
42 changes: 28 additions & 14 deletions packages/next/src/server/request/search-params.browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,18 +119,32 @@ function makeUntrackedExoticSearchParams(
return promise
}

function warnForSyncAccess(expression: string) {
console.error(
`A searchParam property was accessed directly with ${expression}. ` +
`\`searchParams\` should be unwrapped with \`React.use()\` before accessing its properties. ` +
`Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis`
)
}
const noop = () => {}

function warnForSyncSpread() {
console.error(
`The keys of \`searchParams\` were accessed directly. ` +
`\`searchParams\` should be unwrapped with \`React.use()\` before accessing its properties. ` +
`Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis`
)
}
const warnForSyncAccess = process.env.__NEXT_DISABLE_SYNC_DYNAMIC_API_WARNINGS
? noop
: function warnForSyncAccess(expression: string) {
if (process.env.__NEXT_DISABLE_SYNC_DYNAMIC_API_WARNINGS) {
return
}

console.error(
`A searchParam property was accessed directly with ${expression}. ` +
`\`searchParams\` should be unwrapped with \`React.use()\` before accessing its properties. ` +
`Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis`
)
}

const warnForSyncSpread = process.env.__NEXT_DISABLE_SYNC_DYNAMIC_API_WARNINGS
? noop
: function warnForSyncSpread() {
if (process.env.__NEXT_DISABLE_SYNC_DYNAMIC_API_WARNINGS) {
return
}

console.error(
`The keys of \`searchParams\` were accessed directly. ` +
`\`searchParams\` should be unwrapped with \`React.use()\` before accessing its properties. ` +
`Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis`
)
}
Loading

0 comments on commit accec7b

Please sign in to comment.