Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow silencing direct access of dynamic APIs to unblock internal sync #70705

Merged
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
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 ??
huozhi marked this conversation as resolved.
Show resolved Hide resolved
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) {
Comment on lines +515 to +518
Copy link
Member Author

Choose a reason for hiding this comment

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

Could've been early return but this works nicer with #70672

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
Loading