diff --git a/UPGRADING.md b/UPGRADING.md index 458bc5783e5d076..83373e6ae0ad5dd 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -1,213 +1 @@ -# Migrating from v8 to v9 - -## Preamble - -#### Production Deployment on ZEIT Now v2 - -If you previously configured `routes` in your `now.json` file for dynamic routes, these rules can be removed when leveraging Next.js 9's new [Dynamic Routing feature](https://github.com/zeit/next.js#dynamic-routing). - -Next.js 9's dynamic routes are **automatically configured on [Now](https://zeit.co/now)** and do not require any `now.json` customization. - -You can read more about [Dynamic Routing here](https://github.com/zeit/next.js#dynamic-routing). - -#### Check your Custom (`pages/_app.js`) - -If you previously copied the [Custom ``](https://nextjs.org/docs#custom-app) example, you may be able to remove your `getInitialProps`. - -Removing `getInitialProps` from `pages/_app.js` (when possible) is important to leverage new Next.js features! - -The following `getInitialProps` does nothing and may be removed: - -```js -class MyApp extends App { - // Remove me, I do nothing! - static async getInitialProps({ Component, ctx }) { - let pageProps = {} - - if (Component.getInitialProps) { - pageProps = await Component.getInitialProps(ctx) - } - - return { pageProps } - } - - render() { - // ... etc - } -} -``` - -## Breaking Changes - -#### `@zeit/next-typescript` is no longer necessary - -Next.js will now ignore usage `@zeit/next-typescript` and warn you to remove it. Please remove this plugin from your `next.config.js`. - -Remove references to `@zeit/next-typescript/babel` from your custom `.babelrc` (if present). - -Usage of [`fork-ts-checker-webpack-plugin`](https://github.com/Realytics/fork-ts-checker-webpack-plugin/issues) should also be removed from your `next.config.js`. - -TypeScript Definitions are published with the `next` package, so you need to uninstall `@types/next` as they would conflict. - -The following types are different: - -> This list was created by the community to help you upgrade, if you find other differences please send a pull-request to this list to help other users. - -From: - -```tsx -import { NextContext } from 'next' -import { NextAppContext, DefaultAppIProps } from 'next/app' -import { NextDocumentContext, DefaultDocumentIProps } from 'next/document' -``` - -to - -```tsx -import { NextPageContext } from 'next' -import { AppContext, AppInitialProps } from 'next/app' -import { DocumentContext, DocumentInitialProps } from 'next/document' -``` - -#### The `config` key is now a special export on a page - -You may no longer export a custom variable named `config` from a page (i.e. `export { config }` / `export const config ...`). -This exported variable is now used to specify page-level Next.js configuration like Opt-in AMP and API Route features. - -You must rename a non-Next.js-purposed `config` export to something different. - -#### `next/dynamic` no longer renders "loading..." by default while loading - -Dynamic components will not render anything by default while loading. You can still customize this behavior by setting the `loading` property: - -```jsx -import dynamic from 'next/dynamic' - -const DynamicComponentWithCustomLoading = dynamic( - () => import('../components/hello2'), - { - loading: () =>

Loading

, - } -) -``` - -#### `withAmp` has been removed in favor of an exported configuration object - -Next.js now has the concept of page-level configuration, so the `withAmp` higher-order component has been removed for consistency. - -This change can be **automatically migrated by running the following commands in the root of your Next.js project:** - -```bash -curl -L https://github.com/zeit/next-codemod/archive/master.tar.gz | tar -xz --strip=2 next-codemod-master/transforms/withamp-to-config.js npx jscodeshift -t ./withamp-to-config.js pages/**/*.js -``` - -To perform this migration by hand, or view what the codemod will produce, see below: - -**Before** - -```jsx -import { withAmp } from 'next/amp' - -function Home() { - return

My AMP Page

-} - -export default withAmp(Home) -// or -export default withAmp(Home, { hybrid: true }) -``` - -**After** - -```jsx -export default function Home() { - return

My AMP Page

-} - -export const config = { - amp: true, - // or - amp: 'hybrid', -} -``` - -#### `next export` no longer exports pages as `index.html` - -Previously, exporting `pages/about.js` would result in `out/about/index.html`. This behavior has been changed to result in `out/about.html`. - -You can revert to the previous behavior by creating a `next.config.js` with the following content: - -```js -// next.config.js -module.exports = { - exportTrailingSlash: true, -} -``` - -#### `./pages/api/` is treated differently - -Pages in `./pages/api/` are now considered [API Routes](https://nextjs.org/blog/next-9#api-routes). -Pages in this directory will no longer contain a client-side bundle. - -## Deprecated Features - -#### `next/dynamic` has deprecated loading multiple modules at once - -The ability to load multiple modules at once has been deprecated in `next/dynamic` to be closer to React's implementation (`React.lazy` and `Suspense`). - -Updating code that relies on this behavior is relatively straightforward! We've provided an example of a before/after to help you migrate your application: - -**Before** - -```jsx -import dynamic from 'next/dynamic' - -const HelloBundle = dynamic({ - modules: () => { - const components = { - Hello1: () => import('../components/hello1').then(m => m.default), - Hello2: () => import('../components/hello2').then(m => m.default), - } - - return components - }, - render: (props, { Hello1, Hello2 }) => ( -
-

{props.title}

- - -
- ), -}) - -function DynamicBundle() { - return -} - -export default DynamicBundle -``` - -**After** - -```jsx -import dynamic from 'next/dynamic' - -const Hello1 = dynamic(() => import('../components/hello1')) -const Hello2 = dynamic(() => import('../components/hello2')) - -function HelloBundle({ title }) { - return ( -
-

{title}

- - -
- ) -} - -function DynamicBundle() { - return -} - -export default DynamicBundle -``` +This document has been moved to [nextjs.org/docs/upgrading](https://nextjs.org/docs/upgrading). It's also available in this repository on [/docs/upgrading.md](/docs/upgrading.md). diff --git a/docs/manifest.json b/docs/manifest.json index b3cccfe61edfd37..fb6dd32df41a138 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -147,6 +147,10 @@ } ] }, + { + "title": "Upgrade Guide", + "path": "/docs/upgrading.md" + }, { "title": "FAQ", "path": "/docs/faq.md" } ] }, diff --git a/docs/upgrading.md b/docs/upgrading.md new file mode 100644 index 000000000000000..979d9c3195e6aa1 --- /dev/null +++ b/docs/upgrading.md @@ -0,0 +1,219 @@ +--- +description: Learn how to upgrade Next.js. +--- + +# Upgrade Guide + +## Upgrading from version 8 to 9.0.x + +### Preamble + +#### Production Deployment on ZEIT Now v2 + +If you previously configured `routes` in your `now.json` file for dynamic routes, these rules can be removed when leveraging Next.js 9's new [Dynamic Routing feature](https://github.com/zeit/next.js#dynamic-routing). + +Next.js 9's dynamic routes are **automatically configured on [Now](https://zeit.co/now)** and do not require any `now.json` customization. + +You can read more about [Dynamic Routing here](https://github.com/zeit/next.js#dynamic-routing). + +#### Check your Custom (`pages/_app.js`) + +If you previously copied the [Custom ``](https://nextjs.org/docs#custom-app) example, you may be able to remove your `getInitialProps`. + +Removing `getInitialProps` from `pages/_app.js` (when possible) is important to leverage new Next.js features! + +The following `getInitialProps` does nothing and may be removed: + +```js +class MyApp extends App { + // Remove me, I do nothing! + static async getInitialProps({ Component, ctx }) { + let pageProps = {} + + if (Component.getInitialProps) { + pageProps = await Component.getInitialProps(ctx) + } + + return { pageProps } + } + + render() { + // ... etc + } +} +``` + +### Breaking Changes + +#### `@zeit/next-typescript` is no longer necessary + +Next.js will now ignore usage `@zeit/next-typescript` and warn you to remove it. Please remove this plugin from your `next.config.js`. + +Remove references to `@zeit/next-typescript/babel` from your custom `.babelrc` (if present). + +Usage of [`fork-ts-checker-webpack-plugin`](https://github.com/Realytics/fork-ts-checker-webpack-plugin/issues) should also be removed from your `next.config.js`. + +TypeScript Definitions are published with the `next` package, so you need to uninstall `@types/next` as they would conflict. + +The following types are different: + +> This list was created by the community to help you upgrade, if you find other differences please send a pull-request to this list to help other users. + +From: + +```tsx +import { NextContext } from 'next' +import { NextAppContext, DefaultAppIProps } from 'next/app' +import { NextDocumentContext, DefaultDocumentIProps } from 'next/document' +``` + +to + +```tsx +import { NextPageContext } from 'next' +import { AppContext, AppInitialProps } from 'next/app' +import { DocumentContext, DocumentInitialProps } from 'next/document' +``` + +#### The `config` key is now a special export on a page + +You may no longer export a custom variable named `config` from a page (i.e. `export { config }` / `export const config ...`). +This exported variable is now used to specify page-level Next.js configuration like Opt-in AMP and API Route features. + +You must rename a non-Next.js-purposed `config` export to something different. + +#### `next/dynamic` no longer renders "loading..." by default while loading + +Dynamic components will not render anything by default while loading. You can still customize this behavior by setting the `loading` property: + +```jsx +import dynamic from 'next/dynamic' + +const DynamicComponentWithCustomLoading = dynamic( + () => import('../components/hello2'), + { + loading: () =>

Loading

, + } +) +``` + +#### `withAmp` has been removed in favor of an exported configuration object + +Next.js now has the concept of page-level configuration, so the `withAmp` higher-order component has been removed for consistency. + +This change can be **automatically migrated by running the following commands in the root of your Next.js project:** + +```bash +curl -L https://github.com/zeit/next-codemod/archive/master.tar.gz | tar -xz --strip=2 next-codemod-master/transforms/withamp-to-config.js npx jscodeshift -t ./withamp-to-config.js pages/**/*.js +``` + +To perform this migration by hand, or view what the codemod will produce, see below: + +**Before** + +```jsx +import { withAmp } from 'next/amp' + +function Home() { + return

My AMP Page

+} + +export default withAmp(Home) +// or +export default withAmp(Home, { hybrid: true }) +``` + +**After** + +```jsx +export default function Home() { + return

My AMP Page

+} + +export const config = { + amp: true, + // or + amp: 'hybrid', +} +``` + +#### `next export` no longer exports pages as `index.html` + +Previously, exporting `pages/about.js` would result in `out/about/index.html`. This behavior has been changed to result in `out/about.html`. + +You can revert to the previous behavior by creating a `next.config.js` with the following content: + +```js +// next.config.js +module.exports = { + exportTrailingSlash: true, +} +``` + +#### `./pages/api/` is treated differently + +Pages in `./pages/api/` are now considered [API Routes](https://nextjs.org/blog/next-9#api-routes). +Pages in this directory will no longer contain a client-side bundle. + +## Deprecated Features + +#### `next/dynamic` has deprecated loading multiple modules at once + +The ability to load multiple modules at once has been deprecated in `next/dynamic` to be closer to React's implementation (`React.lazy` and `Suspense`). + +Updating code that relies on this behavior is relatively straightforward! We've provided an example of a before/after to help you migrate your application: + +**Before** + +```jsx +import dynamic from 'next/dynamic' + +const HelloBundle = dynamic({ + modules: () => { + const components = { + Hello1: () => import('../components/hello1').then(m => m.default), + Hello2: () => import('../components/hello2').then(m => m.default), + } + + return components + }, + render: (props, { Hello1, Hello2 }) => ( +
+

{props.title}

+ + +
+ ), +}) + +function DynamicBundle() { + return +} + +export default DynamicBundle +``` + +**After** + +```jsx +import dynamic from 'next/dynamic' + +const Hello1 = dynamic(() => import('../components/hello1')) +const Hello2 = dynamic(() => import('../components/hello2')) + +function HelloBundle({ title }) { + return ( +
+

{title}

+ + +
+ ) +} + +function DynamicBundle() { + return +} + +export default DynamicBundle +```