Skip to content

Commit

Permalink
Merge branch 'canary' into patch-2
Browse files Browse the repository at this point in the history
  • Loading branch information
xugetsu authored Sep 23, 2024
2 parents 05f174f + 64fdbcb commit c791994
Show file tree
Hide file tree
Showing 92 changed files with 2,039 additions and 85 deletions.
102 changes: 102 additions & 0 deletions docs/02-app/01-building-your-application/11-upgrading/01-codemods.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,108 @@ Replacing `<transform>` and `<path>` with appropriate values.

### 15.0

#### Migrate to async Dynamic APIs

##### `next-async-request-api`

```bash filename="Terminal"
npx @next/codemod@latest next-async-request-api .
```

This codemod will transform APIs `cookies()`, `headers()` and `draftMode()` from `next/headers` to be properly awaited or wrapped with `React.use()` if needed.
If it's not able to be migrated, will either add a type cast or a TODO comment based on the file is a TypeScript or JavaScript file.

For example:

```tsx
import { cookies, headers } from 'next/headers'
const token = cookies().get('token')

function useToken() {
const token = cookies().get('token')
return token
}

export default function Page() {
const name = cookies().get('name')
}

function getHeader() {
return headers().get('x-foo')
}
```

Transforms into:

```tsx
import { use } from 'react'
import { cookies, headers, type UnsafeUnwrappedCookies } from 'next/headers'

const token = (await cookies()).get('token')

function useToken() {
const token = use(cookies()).get('token')
return token
}

export default function Page() {
const name = (await cookies()).get('name')
}

function getHeader() {
return (headers() as UnsafeUnwrappedCookies).get('x-foo')
}
```

If there's access to the entry handler `params` and `searchParams` in the route entry default handler (`page.js`, `layout.js`, `route.js` or Metadata API routes) or `generateMetadata` export API,
it will transform the access to the property from sync to async, and await or wrap these properties with `React.use()` if needed.

For example:

```tsx
// page.tsx
export default function Page({
params,
searchParams,
}: {
params: { slug: string }
searchParams: { [key: string]: string | undefined }
}) {
const { value } = searchParams
if (value === 'foo') {
// ...
}
}

export function generateMetadata({ params }: { params: { slug: string } }) {
return {
title: `My Page - ${slug}`,
}
}
```

Transforms into:

```tsx
// page.tsx
export default function Page(props: {
params: { slug: string }
searchParams: { [key: string]: string | undefined }
}) {
const { value } = await props.searchParams
if (value === 'foo') {
// ...
}
}

export function generateMetadata(props: { params: { slug: string } }) {
const { slug } = await props.params
return {
title: `My Page - ${slug}`,
}
}
```

#### Replace `geo` and `ip` properties of `NextRequest` with `@vercel/functions`

##### `next-request-geo-ip`
Expand Down
4 changes: 4 additions & 0 deletions packages/next-codemod/bin/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,10 @@ const TRANSFORMER_INQUIRER_CHOICES = [
name: 'built-in-next-font: Uninstall `@next/font` and transform imports to `next/font`',
value: 'built-in-next-font',
},
{
name: 'next-async-request-api: Transforms usage of Next.js async Request APIs',
value: 'next-async-request-api',
},
{
name: 'next-request-geo-ip: Install `@vercel/functions` to replace `geo` and `ip` properties on `NextRequest`',
value: 'next-request-geo-ip',
Expand Down
1 change: 1 addition & 0 deletions packages/next-codemod/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
},
"files": [
"transforms/*.js",
"transforms/lib/**/*.js",
"bin/*.js",
"lib/**/*.js",
"lib/cra-to-next/gitignore"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { cookies } from 'next/headers'

export async function MyComponent() {
const name = cookies().get('name')
callback(name)
}

function callback(name: any) {
console.log(name)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { cookies } from 'next/headers'

export async function MyComponent() {
const name = (await cookies()).get('name')
callback(name)
}

function callback(name: any) {
console.log(name)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { draftMode } from 'next/headers'

export async function MyComponent() {
draftMode().enable()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { draftMode } from 'next/headers'

export async function MyComponent() {
(await draftMode()).enable()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// If it's sync default export, convert to async and await the function call
import { draftMode } from 'next/headers'

export default function MyComponent() {
draftMode().enable()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// If it's sync default export, convert to async and await the function call
import { draftMode } from 'next/headers'

export default async function MyComponent() {
(await draftMode()).enable()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { draftMode } from 'next/headers'

export default async function MyComponent() {
draftMode().enable()
}

export async function MyComponent2() {
draftMode().enable()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { draftMode } from 'next/headers'

export default async function MyComponent() {
(await draftMode()).enable()
}

export async function MyComponent2() {
(await draftMode()).enable()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { draftMode } from 'next/headers'

export function MyComponent2() {
draftMode().enable()
}

export function useDraftModeEnabled() {
draftMode().enable()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { use } from "react";
import { draftMode, type UnsafeUnwrappedDraftMode } from 'next/headers';

export function MyComponent2() {
(draftMode() as unknown as UnsafeUnwrappedDraftMode).enable()
}

export function useDraftModeEnabled() {
use(draftMode()).enable()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import React from 'react'
import { draftMode } from 'next/headers'

export default function Page() {
return <button disabled={draftMode().isEnabled}>Enable Draft Mode</button>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import React from 'react'
import { draftMode } from 'next/headers'

export default async function Page() {
return <button disabled={(await draftMode()).isEnabled}>Enable Draft Mode</button>;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Already imported the type
import { draftMode, type UnsafeUnwrappedDraftMode } from 'next/headers'

export function MyComponent2() {
draftMode().enable()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Already imported the type
import { draftMode, type UnsafeUnwrappedDraftMode } from 'next/headers'

export function MyComponent2() {
(draftMode() as unknown as UnsafeUnwrappedDraftMode).enable()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { headers } from 'next/headers'

export function GET(): Response {
headers()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { headers } from 'next/headers'

export async function GET(): Promise<Response> {
await headers()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export default function Page({
params: { slug },
searchParams: { search },
}: {
params: { slug: string }
searchParams: any
}): JSX.Element {
// Access to the destructed properties
slug
search

return <div>Page</div>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export default async function Page(
props: {
params: Promise<{ slug: string }>
searchParams: Promise<any>
}
): Promise<JSX.Element> {
const searchParams = await props.searchParams;

const {
search
} = searchParams;

const params = await props.params;

const {
slug
} = params;

// Access to the destructed properties
slug
search

return <div>Page</div>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { headers } from 'next/headers'

export function MyComp() {
return headers()
}

export function MyComp2() {
return headers()
}

export function MyComp3() {
return headers()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { headers, type UnsafeUnwrappedHeaders } from 'next/headers';

export function MyComp() {
return (headers() as unknown as UnsafeUnwrappedHeaders);
}

export function MyComp2() {
return (headers() as unknown as UnsafeUnwrappedHeaders);
}

export function MyComp3() {
return (headers() as unknown as UnsafeUnwrappedHeaders);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { headers } from 'next/headers'

export function MyComp() {
headers()
}

export function generateContentfulMetadata() {
headers()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { headers, type UnsafeUnwrappedHeaders } from 'next/headers';

export function MyComp() {
(headers() as unknown as UnsafeUnwrappedHeaders)
}

export function generateContentfulMetadata() {
(headers() as unknown as UnsafeUnwrappedHeaders)
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { cookies } from "next/headers";

async function MyComponent() {
callSomething(cookies());
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { cookies } from "next/headers";

async function MyComponent() {
callSomething(await cookies());
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { headers } from "next/headers";

async function MyComponent() {
callSomething(headers());
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { headers } from "next/headers";

async function MyComponent() {
callSomething(await headers());
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { cookies } from "next/headers";

export default async function Page() {
callSomething(cookies());
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { cookies } from "next/headers";

export default async function Page() {
callSomething(await cookies());
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { cookies } from "next/headers";

async function MyComponent() {
function asyncFunction() {
callSomething(cookies());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { cookies } from "next/headers";

async function MyComponent() {
function asyncFunction() {
callSomething(/* TODO: please manually await this call, codemod cannot transform due to undetermined async scope */
cookies());
}
}
Loading

0 comments on commit c791994

Please sign in to comment.