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

Bump minimum suggested React version #21046

Merged
merged 10 commits into from Jan 15, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
34 changes: 30 additions & 4 deletions .github/workflows/build_test_deploy.yml
Expand Up @@ -154,7 +154,7 @@ jobs:
- run: exit 0

testFutureDependencies:
name: React 17 + webpack 5 (Basic, Production, Acceptance)
name: Webpack 5 (Basic, Production, Acceptance)
runs-on: ubuntu-latest
env:
NEXT_TELEMETRY_DISABLED: 1
Expand All @@ -171,16 +171,42 @@ jobs:
- run: git fetch --depth=1 origin +refs/tags/*:refs/tags/*
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs-only' }}

- run: cat package.json | jq '.resolutions.react = "^17.0.1"' > package.json.tmp && mv package.json.tmp package.json
- run: yarn install --check-files
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs-only' }}

- run: yarn list webpack
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs-only' }}

- run: xvfb-run node run-tests.js test/integration/{link-ref,production,basic,async-modules,ssr-ctx}/test/index.test.js test/acceptance/*.test.js
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs-only' }}

testLegacyReact:
name: React 16 + Webpack 4 (Basic, Production, Acceptance)
runs-on: ubuntu-latest
env:
NEXT_TELEMETRY_DISABLED: 1
NEXT_TEST_JOB: 1
HEADLESS: true

steps:
- uses: actions/checkout@v2

- run: echo ::set-output name=DOCS_CHANGE::$(node skip-docs-change.js echo 'docs-only')
id: docs-change

- run: git fetch --depth=1 origin +refs/tags/*:refs/tags/*
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs-only' }}

- run: cat package.json | jq '.resolutions.react = "^16.14.0"' > package.json.tmp && mv package.json.tmp package.json
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs-only' }}

- run: cat package.json | jq '.resolutions."react-dom" = "^17.0.1"' > package.json.tmp && mv package.json.tmp package.json
- run: cat package.json | jq '.resolutions."react-dom" = "^16.14.0"' > package.json.tmp && mv package.json.tmp package.json
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs-only' }}

- run: yarn install --check-files
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs-only' }}

- run: yarn list webpack react react-dom
- run: yarn list react react-dom
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs-only' }}

- run: xvfb-run node run-tests.js test/integration/{link-ref,production,basic,async-modules,ssr-ctx,worker-loader}/test/index.test.js test/acceptance/*.test.js
Expand Down
6 changes: 3 additions & 3 deletions errors/react-version.md
Expand Up @@ -5,7 +5,7 @@
Your project is using an old version of `react` or `react-dom` that does not
meet the suggested minimum version requirement.

Next.js suggests using, at a minimum, `react@16.10.0` and `react-dom@16.10.0`.
Next.js suggests using, at a minimum, `react@17.0.1` and `react-dom@17.0.1`.
Older versions of `react` and `react-dom` do work with Next.js, however, they do
not enable all of Next.js' features.

Expand Down Expand Up @@ -39,8 +39,8 @@ yarn add react@latest react-dom@latest
```json
{
"dependencies": {
"react": "^16.10.0",
"react-dom": "^16.10.0"
"react": "^17.0.1",
"react-dom": "^17.0.1"
}
}
```
Expand Down
4 changes: 2 additions & 2 deletions package.json
Expand Up @@ -115,8 +115,8 @@
"prettier": "2.0.5",
"pretty-bytes": "5.3.0",
"pretty-ms": "7.0.0",
"react": "16.12.0",
"react-dom": "16.12.0",
"react": "17.0.1",
"react-dom": "17.0.1",
"react-ssr-prepass": "1.0.8",
"release": "6.3.0",
"request-promise-core": "1.1.2",
Expand Down
Expand Up @@ -122,6 +122,10 @@ export class FontStylesheetGatheringPlugin {
parser.hooks.call
.for('__jsx')
.tap(this.constructor.name, jsxNodeHandler)
// New React JSX transform:
parser.hooks.call
.for('imported var')
devknoll marked this conversation as resolved.
Show resolved Hide resolved
.tap(this.constructor.name, jsxNodeHandler)
})
}
}
Expand Down
49 changes: 44 additions & 5 deletions packages/next/cli/next-build.ts
Expand Up @@ -55,11 +55,50 @@ const nextBuild: cliCommand = (argv) => {
printAndExit(`> No such directory exists as the project root: ${dir}`)
}

return build(dir, null, args['--profile'], args['--debug']).catch((err) => {
console.error('')
console.error('> Build error occurred')
printAndExit(err)
})
async function preflight() {
const { getPackageVersion } = await import('../lib/get-package-version')
const semver = await import('next/dist/compiled/semver').then(
(res) => res.default
)

const reactVersion: string | null = await getPackageVersion({
cwd: dir,
name: 'react',
})
if (
reactVersion &&
semver.lt(reactVersion, '17.0.1') &&
semver.coerce(reactVersion)?.version !== '0.0.0'
) {
Log.warn(
'React 17.0.1 or newer will be required to leverage all of the upcoming features in Next.js 11.' +
' Read more: https://err.sh/next.js/react-version'
)
} else {
const reactDomVersion: string | null = await getPackageVersion({
cwd: dir,
name: 'react-dom',
})
if (
reactDomVersion &&
semver.lt(reactDomVersion, '17.0.1') &&
semver.coerce(reactDomVersion)?.version !== '0.0.0'
) {
Log.warn(
'React 17.0.1 or newer will be required to leverage all of the upcoming features in Next.js 11.' +
' Read more: https://err.sh/next.js/react-version'
)
}
}
}

return preflight()
.then(() => build(dir, null, args['--profile'], args['--debug']))
.catch((err) => {
console.error('')
console.error('> Build error occurred')
printAndExit(err)
})
}

export { nextBuild }
8 changes: 4 additions & 4 deletions packages/next/cli/next-dev.ts
Expand Up @@ -68,11 +68,11 @@ const nextDev: cliCommand = (argv) => {
})
if (
reactVersion &&
semver.lt(reactVersion, '16.10.0') &&
semver.lt(reactVersion, '17.0.1') &&
semver.coerce(reactVersion)?.version !== '0.0.0'
) {
Log.warn(
'Fast Refresh is disabled in your application due to an outdated `react` version. Please upgrade 16.10 or newer!' +
'React 17.0.1 or newer will be required to leverage all of the upcoming features in Next.js 11.' +
' Read more: https://err.sh/next.js/react-version'
)
} else {
Expand All @@ -82,11 +82,11 @@ const nextDev: cliCommand = (argv) => {
})
if (
reactDomVersion &&
semver.lt(reactDomVersion, '16.10.0') &&
semver.lt(reactDomVersion, '17.0.1') &&
semver.coerce(reactDomVersion)?.version !== '0.0.0'
) {
Log.warn(
'Fast Refresh is disabled in your application due to an outdated `react-dom` version. Please upgrade 16.10 or newer!' +
'React 17.0.1 or newer will be required to leverage all of the upcoming features in Next.js 11.' +
' Read more: https://err.sh/next.js/react-version'
)
}
Expand Down
12 changes: 6 additions & 6 deletions test/integration/build-output/test/index.test.js
Expand Up @@ -94,17 +94,17 @@ describe('Build Output', () => {
expect(parseFloat(indexSize) - 266).toBeLessThanOrEqual(0)
expect(indexSize.endsWith('B')).toBe(true)

// should be no bigger than 62.2 kb
expect(parseFloat(indexFirstLoad)).toBeCloseTo(62.4, 1)
// should be no bigger than 63.8 kb
expect(parseFloat(indexFirstLoad)).toBeCloseTo(63.8, 1)
expect(indexFirstLoad.endsWith('kB')).toBe(true)

expect(parseFloat(err404Size) - 3.7).toBeLessThanOrEqual(0)
expect(err404Size.endsWith('kB')).toBe(true)

expect(parseFloat(err404FirstLoad)).toBeCloseTo(65.6, 1)
expect(parseFloat(err404FirstLoad)).toBeCloseTo(67, 1)
expect(err404FirstLoad.endsWith('kB')).toBe(true)

expect(parseFloat(sharedByAll)).toBeCloseTo(62.1, 1)
expect(parseFloat(sharedByAll)).toBeCloseTo(63.5, 1)
expect(sharedByAll.endsWith('kB')).toBe(true)

if (_appSize.endsWith('kB')) {
Expand All @@ -121,7 +121,7 @@ describe('Build Output', () => {
expect(parseFloat(mainSize) - 7.3).toBeLessThanOrEqual(0)
expect(mainSize.endsWith('kB')).toBe(true)

expect(parseFloat(frameworkSize) - 42).toBeLessThanOrEqual(0)
expect(parseFloat(frameworkSize) - 42.1).toBeLessThanOrEqual(0)
expect(frameworkSize.endsWith('kB')).toBe(true)
})

Expand Down Expand Up @@ -168,7 +168,7 @@ describe('Build Output', () => {
expect(parseFloat(indexSize)).toBeGreaterThanOrEqual(2)
expect(indexSize.endsWith('kB')).toBe(true)

expect(parseFloat(indexFirstLoad)).toBeLessThanOrEqual(65.2)
expect(parseFloat(indexFirstLoad)).toBeLessThanOrEqual(66.6)
expect(parseFloat(indexFirstLoad)).toBeGreaterThanOrEqual(60)
expect(indexFirstLoad.endsWith('kB')).toBe(true)
})
Expand Down
117 changes: 107 additions & 10 deletions test/integration/cli/test/index.test.js
Expand Up @@ -115,6 +115,69 @@ describe('CLI Usage', () => {
expect(code).toBe(expectedExitCode)
expect(signal).toBe(expectedExitSignal)
})

test('too old of react version', async () => {
const { stderr } = await runNextCommand(['build', dirOldReact], {
stderr: true,
})

expect(stderr).toMatch(
'React 17.0.1 or newer will be required to leverage all of the upcoming features in Next.js 11.'
)
})

test('too old of react-dom version', async () => {
const { stderr } = await runNextCommand(['build', dirOldReactDom], {
stderr: true,
})

expect(stderr).toMatch(
'React 17.0.1 or newer will be required to leverage all of the upcoming features in Next.js 11.'
)
})

test('experimental react version', async () => {
const { stderr } = await runNextCommand(['build', dirExperimentalReact], {
stderr: true,
})

expect(stderr).not.toMatch(
'React 17.0.1 or newer will be required to leverage all of the upcoming features in Next.js 11.'
)
})

test('experimental react-dom version', async () => {
const { stderr } = await runNextCommand(
['build', dirExperimentalReactDom],
{
stderr: true,
}
)

expect(stderr).not.toMatch(
'React 17.0.1 or newer will be required to leverage all of the upcoming features in Next.js 11.'
)
})

test('recommended react version', async () => {
const { stderr } = await runNextCommand(['build'], {
stderr: true,
})

expect(stderr).not.toMatch(
'React 17.0.1 or newer will be required to leverage all of the upcoming features in Next.js 11.'
)
})

test('recommended react-dom version', async () => {
const { stderr } = await runNextCommand(['build'], {
stderr: true,
})

expect(stderr).not.toMatch(
'React 17.0.1 or newer will be required to leverage all of the upcoming features in Next.js 11.'
)
})
})

describe('dev', () => {
Expand Down Expand Up @@ -296,9 +359,8 @@ describe('CLI Usage', () => {
})

expect(stderr).toMatch(
'Fast Refresh is disabled in your application due to an outdated `react` version'
'React 17.0.1 or newer will be required to leverage all of the upcoming features in Next.js 11.'
)
expect(stderr).not.toMatch(`react-dom`)

await killApp(instance)
})
Expand All @@ -315,9 +377,8 @@ describe('CLI Usage', () => {
})

expect(stderr).toMatch(
'Fast Refresh is disabled in your application due to an outdated `react-dom` version'
'React 17.0.1 or newer will be required to leverage all of the upcoming features in Next.js 11.'
)
expect(stderr).not.toMatch('`react`')

await killApp(instance)
})
Expand All @@ -333,9 +394,9 @@ describe('CLI Usage', () => {
},
})

expect(stderr).not.toMatch('disabled')
expect(stderr).not.toMatch('outdated')
expect(stderr).not.toMatch(`react-dom`)
expect(stderr).not.toMatch(
'React 17.0.1 or newer will be required to leverage all of the upcoming features in Next.js 11.'
)

await killApp(instance)
})
Expand All @@ -351,9 +412,45 @@ describe('CLI Usage', () => {
},
})

expect(stderr).not.toMatch('disabled')
expect(stderr).not.toMatch('outdated')
expect(stderr).not.toMatch('`react`')
expect(stderr).not.toMatch(
'React 17.0.1 or newer will be required to leverage all of the upcoming features in Next.js 11.'
)

await killApp(instance)
})

test('recommended react version', async () => {
const port = await findPort()

let stderr = ''
let instance = await launchApp(dir, port, {
stderr: true,
onStderr(msg) {
stderr += msg
},
})

expect(stderr).not.toMatch(
'React 17.0.1 or newer will be required to leverage all of the upcoming features in Next.js 11.'
)

await killApp(instance)
})

test('recommended react-dom version', async () => {
const port = await findPort()

let stderr = ''
let instance = await launchApp(dir, port, {
stderr: true,
onStderr(msg) {
stderr += msg
},
})

expect(stderr).not.toMatch(
'React 17.0.1 or newer will be required to leverage all of the upcoming features in Next.js 11.'
)

await killApp(instance)
})
Expand Down
2 changes: 1 addition & 1 deletion test/integration/size-limit/test/index.test.js
Expand Up @@ -81,6 +81,6 @@ describe('Production response size', () => {
const delta = responseSizesBytes / 1024

// Expected difference: < 0.5
expect(delta).toBeCloseTo(282.6, 0)
expect(delta).toBeCloseTo(284.1, 0)
})
})