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

Remove deprecated features #25446

Merged
merged 11 commits into from
Jun 2, 2021
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
32 changes: 32 additions & 0 deletions docs/upgrading.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,38 @@ description: Learn how to upgrade Next.js.

# Upgrade Guide

## Upgrading from version 10 to 11

### Remove `super.componentDidCatch()` from `pages/_app.js`

The `next/app` component's `componentDidCatch` has been deprecated since Next.js 9 as it's no longer needed and has since been a no-op, in Next.js 11 it has been removed.

If your `pages/_app.js` has a custom `componentDidCatch` method you can remove `super.componentDidCatch` as it is no longer needed.

### Remove `Container` from `pages/_app.js`

This export has been deprecated since Next.js 9 as it's no longer needed and has since been a no-op with a warning during development. In Next.js 11 it has been removed.

If your `pages/_app.js` imports `Container` from `next/app` you can remove `Container` as it has been removed. Learn more in [the documentation](https://nextjs.org/docs/messages/app-container-deprecated).

### Remove `props.url` usage from page components

This property has been deprecated since Next.js 4 and has since shown a warning during development. With the introduction of `getStaticProps` / `getServerSideProps` these methods already disallowed usage of `props.url`. In Next.js 11 it has been removed completely.

You can learn more in [the documentation](https://nextjs.org/docs/messages/url-deprecated).

### Remove `unsized` property on `next/image`

The `unsized` property on `next/image` was deprecated in Next.js 10.0.1. You can use `layout="fill"` instead. In Next.js 11 `unsized` was removed.

### Remove `modules` property on `next/dynamic`

The `modules` and `render` option for `next/dynamic` have been deprecated since Next.js 9.5 showing a warning that it has been deprecated. This was done in order to make `next/dynamic` close to `React.lazy` in API surface. In Next.js 11 the `modules` and `render` options have been removed.

This option hasn't been mentioned in the documentation since Next.js 8 so it's less likely that your application is using it.

If you application does use `modules` and `render` you can refer to [the documentation](https://nextjs.org/docs/messages/next-dynamic-modules).

## React 16 to 17

React 17 introduced a new [JSX Transform](https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html) that brings a long-time Next.js feature to the wider React ecosystem: Not having to `import React from 'react'` when using JSX. When using React 17 Next.js will automatically use the new transform. This transform does not make the `React` variable global, which was an unintended side-effect of the previous Next.js implementation. A [codemod is available](/docs/advanced-features/codemods.md#add-missing-react-import) to automatically fix cases where you accidentally used `React` without importing it.
Expand Down
23 changes: 1 addition & 22 deletions packages/next/client/image.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,6 @@ export type ImageProps = Omit<
objectFit?: ImgElementStyle['objectFit']
objectPosition?: ImgElementStyle['objectPosition']
} & (
| {
width?: never
height?: never
/** @deprecated Use `layout="fill"` instead */
unsized: true
}
| { width?: never; height?: never; layout: 'fill' }
| {
width: number | string
Expand Down Expand Up @@ -260,12 +254,7 @@ export default function Image({
}: ImageProps) {
let rest: Partial<ImageProps> = all
let layout: NonNullable<LayoutValue> = sizes ? 'responsive' : 'intrinsic'
let unsized = false
if ('unsized' in rest) {
unsized = Boolean(rest.unsized)
// Remove property so it's not spread into image:
delete rest['unsized']
} else if ('layout' in rest) {
if ('layout' in rest) {
// Override default layout if the user specified one:
if (rest.layout) layout = rest.layout

Expand Down Expand Up @@ -304,11 +293,6 @@ export default function Image({
`Image with src "${src}" has both "priority" and "loading='lazy'" properties. Only one should be used.`
)
}
if (unsized) {
throw new Error(
`Image with src "${src}" has deprecated "unsized" property, which was removed in favor of the "layout='fill'" property`
)
}
}

let isLazy =
Expand Down Expand Up @@ -461,11 +445,6 @@ export default function Image({
})
}

if (unsized) {
wrapperStyle = undefined
sizerStyle = undefined
imgStyle = undefined
}
return (
<div style={wrapperStyle}>
{sizerStyle ? (
Expand Down
45 changes: 2 additions & 43 deletions packages/next/next-server/lib/dynamic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,9 @@ export type LoadableBaseOptions<P = {}> = LoadableGeneratedOptions & {
ssr?: boolean
}

export type LoadableOptions<P = {}> = LoadableBaseOptions<P> & {
render?(loader: any, props: any): JSX.Element
}
export type LoadableOptions<P = {}> = LoadableBaseOptions<P>

export type DynamicOptions<P = {}> = LoadableBaseOptions<P> & {
/**
* @deprecated the modules option has been planned for removal
*/
render?(props: P, loaded: any): JSX.Element
}
export type DynamicOptions<P = {}> = LoadableBaseOptions<P>

export type LoadableFn<P = {}> = (
opts: LoadableOptions<P>
Expand Down Expand Up @@ -117,40 +110,6 @@ export default function dynamic<P = {}>(
// Support for passing options, eg: dynamic(import('../hello-world'), {loading: () => <p>Loading something</p>})
loadableOptions = { ...loadableOptions, ...options }

if (
typeof dynamicOptions === 'object' &&
!(dynamicOptions instanceof Promise)
) {
// show deprecation warning for `modules` key in development
if (process.env.NODE_ENV !== 'production') {
if (dynamicOptions.modules) {
console.warn(
'The modules option for next/dynamic has been deprecated. See here for more info https://nextjs.org/docs/messages/next-dynamic-modules'
)
}
}
// Support for `render` when using a mapping, eg: `dynamic({ modules: () => {return {HelloWorld: import('../hello-world')}, render(props, loaded) {} } })
if (dynamicOptions.render) {
loadableOptions.render = (loaded, props) =>
dynamicOptions.render!(props, loaded)
}
// Support for `modules` when using a mapping, eg: `dynamic({ modules: () => {return {HelloWorld: import('../hello-world')}, render(props, loaded) {} } })
if (dynamicOptions.modules) {
loadableFn = Loadable.Map
const loadModules: LoaderMap = {}
const modules = dynamicOptions.modules()
Object.keys(modules).forEach((key) => {
const value: any = modules[key]
if (typeof value.then === 'function') {
loadModules[key] = () => value.then((mod: any) => mod.default || mod)
return
}
loadModules[key] = value
})
loadableOptions.loader = loadModules
}
}

// coming from build/babel/plugins/react-loadable-plugin.js
if (loadableOptions.loadableGenerated) {
loadableOptions = {
Expand Down
64 changes: 1 addition & 63 deletions packages/next/next-server/lib/loadable.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,69 +53,17 @@ function load(loader) {
return state
}

function loadMap(obj) {
let state = {
loading: false,
loaded: {},
error: null,
}

let promises = []

try {
Object.keys(obj).forEach((key) => {
let result = load(obj[key])

if (!result.loading) {
state.loaded[key] = result.loaded
state.error = result.error
} else {
state.loading = true
}

promises.push(result.promise)

result.promise
.then((res) => {
state.loaded[key] = res
})
.catch((err) => {
state.error = err
})
})
} catch (err) {
state.error = err
}

state.promise = Promise.all(promises)
.then((res) => {
state.loading = false
return res
})
.catch((err) => {
state.loading = false
throw err
})

return state
}

function resolve(obj) {
return obj && obj.__esModule ? obj.default : obj
}

function render(loaded, props) {
return React.createElement(resolve(loaded), props)
}

function createLoadableComponent(loadFn, options) {
let opts = Object.assign(
{
loader: null,
loading: null,
delay: 200,
timeout: null,
render: render,
webpack: null,
modules: null,
},
Expand Down Expand Up @@ -188,7 +136,7 @@ function createLoadableComponent(loadFn, options) {
retry: subscription.retry,
})
} else if (state.loaded) {
return opts.render(state.loaded, props)
return React.createElement(resolve(state.loaded), props)
} else {
return null
}
Expand Down Expand Up @@ -291,16 +239,6 @@ function Loadable(opts) {
return createLoadableComponent(load, opts)
}

function LoadableMap(opts) {
if (typeof opts.render !== 'function') {
throw new Error('LoadableMap requires a `render(loaded, props)` function')
}

return createLoadableComponent(loadMap, opts)
}

Loadable.Map = LoadableMap

function flushInitializers(initializers, ids) {
let promises = []

Expand Down
92 changes: 3 additions & 89 deletions packages/next/pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React, { ErrorInfo } from 'react'
import React from 'react'
import {
execOnce,
loadGetInitialProps,
AppContextType,
AppInitialProps,
Expand Down Expand Up @@ -36,94 +35,9 @@ export default class App<P = {}, CP = {}, S = {}> extends React.Component<
static origGetInitialProps = appGetInitialProps
static getInitialProps = appGetInitialProps

// Kept here for backwards compatibility.
// When someone ended App they could call `super.componentDidCatch`.
// @deprecated This method is no longer needed. Errors are caught at the top level
componentDidCatch(error: Error, _errorInfo: ErrorInfo): void {
throw error
}

render() {
const { router, Component, pageProps, __N_SSG, __N_SSP } = this
.props as AppProps<CP>

return (
<Component
{...pageProps}
{
// we don't add the legacy URL prop if it's using non-legacy
// methods like getStaticProps and getServerSideProps
...(!(__N_SSG || __N_SSP) ? { url: createUrl(router) } : {})
}
/>
)
}
}

let warnContainer: () => void
let warnUrl: () => void

if (process.env.NODE_ENV !== 'production') {
warnContainer = execOnce(() => {
console.warn(
`Warning: the \`Container\` in \`_app\` has been deprecated and should be removed. https://nextjs.org/docs/messages/app-container-deprecated`
)
})

warnUrl = execOnce(() => {
console.error(
`Warning: the 'url' property is deprecated. https://nextjs.org/docs/messages/url-deprecated`
)
})
}

// @deprecated noop for now until removal
export function Container(p: any) {
if (process.env.NODE_ENV !== 'production') warnContainer()
return p.children
}

export function createUrl(router: Router) {
// This is to make sure we don't references the router object at call time
const { pathname, asPath, query } = router
return {
get query() {
if (process.env.NODE_ENV !== 'production') warnUrl()
return query
},
get pathname() {
if (process.env.NODE_ENV !== 'production') warnUrl()
return pathname
},
get asPath() {
if (process.env.NODE_ENV !== 'production') warnUrl()
return asPath
},
back: () => {
if (process.env.NODE_ENV !== 'production') warnUrl()
router.back()
},
push: (url: string, as?: string) => {
if (process.env.NODE_ENV !== 'production') warnUrl()
return router.push(url, as)
},
pushTo: (href: string, as?: string) => {
if (process.env.NODE_ENV !== 'production') warnUrl()
const pushRoute = as ? href : ''
const pushUrl = as || href

return router.push(pushRoute, pushUrl)
},
replace: (url: string, as?: string) => {
if (process.env.NODE_ENV !== 'production') warnUrl()
return router.replace(url, as)
},
replaceTo: (href: string, as?: string) => {
if (process.env.NODE_ENV !== 'production') warnUrl()
const replaceRoute = as ? href : ''
const replaceUrl = as || href
const { Component, pageProps } = this.props as AppProps<CP>

return router.replace(replaceRoute, replaceUrl)
},
return <Component {...pageProps} />
}
}
Loading