Skip to content

Commit

Permalink
Merge branch 'canary' into remove-qs
Browse files Browse the repository at this point in the history
  • Loading branch information
kodiakhq[bot] authored Aug 6, 2020
2 parents c6df94e + 882288b commit bdf81a5
Show file tree
Hide file tree
Showing 25 changed files with 247 additions and 11 deletions.
51 changes: 51 additions & 0 deletions errors/react-version.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Minimum React Version

#### Why This Error Occurred

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, `[email protected]` and `[email protected]`.
Older versions of `react` and `react-dom` do work with Next.js, however, they do
not enable all of Next.js' features.

For example, the following features are not enabled with old React versions:

- [Fast Refresh](https://nextjs.org/docs/basic-features/fast-refresh): instantly
view edits to your app without losing component state
- Component stack trace in development: see the component tree that lead up to
an error
- Hydration mismatch warnings: trace down discrepancies in your React tree that
cause performance problems

This list is not exhaustive, but illustrative in the value of upgrading React!

#### Possible Ways to Fix It

**Via npm**

```bash
npm upgrade react@latest react-dom@latest
```

**Via Yarn**

```bash
yarn add react@latest react-dom@latest
```

**Manually** Open your `package.json` and upgrade `react` and `react-dom`:

```json
{
"dependencies": {
"react": "^16.10.0",
"react-dom": "^16.10.0"
}
}
```

### Useful Links

- [Fast Refresh blog post](https://nextjs.org/blog/next-9-4#fast-refresh)
- [Fast Refresh docs](https://nextjs.org/docs/basic-features/fast-refresh)
4 changes: 2 additions & 2 deletions packages/next/build/webpack-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ export default async function getBaseWebpackConfig(
} as ClientEntries)
: undefined

let typeScriptPath
let typeScriptPath: string | undefined
try {
typeScriptPath = resolveRequest('typescript', `${dir}/`)
} catch (_) {}
Expand All @@ -302,7 +302,7 @@ export default async function getBaseWebpackConfig(
let jsConfig
// jsconfig is a subset of tsconfig
if (useTypeScript) {
const ts = (await import(typeScriptPath)) as typeof import('typescript')
const ts = (await import(typeScriptPath!)) as typeof import('typescript')
const tsConfig = await getTypeScriptConfiguration(ts, tsConfigPath)
jsConfig = { compilerOptions: tsConfig.options }
}
Expand Down
33 changes: 33 additions & 0 deletions packages/next/cli/next-dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import arg from 'next/dist/compiled/arg/index.js'
import { existsSync } from 'fs'
import startServer from '../server/lib/start-server'
import { printAndExit } from '../server/lib/utils'
import * as Log from '../build/output/log'
import { startedDevelopmentServer } from '../build/output'
import { cliCommand } from '../bin/next'

Expand Down Expand Up @@ -56,6 +57,35 @@ const nextDev: cliCommand = (argv) => {
printAndExit(`> No such directory exists as the project root: ${dir}`)
}

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, '16.10.0')) {
Log.warn(
'Fast Refresh is disabled in your application due to an outdated `react` version. Please upgrade 16.10 or newer!' +
' 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, '16.10.0')) {
Log.warn(
'Fast Refresh is disabled in your application due to an outdated `react-dom` version. Please upgrade 16.10 or newer!' +
' Read more: https://err.sh/next.js/react-version'
)
}
}
}

const port = args['--port'] || 3000
const appUrl = `http://${args['--hostname'] || 'localhost'}:${port}`

Expand All @@ -66,6 +96,9 @@ const nextDev: cliCommand = (argv) => {
)
.then(async (app) => {
startedDevelopmentServer(appUrl)
// Start preflight after server is listening and ignore errors:
preflight().catch(() => {})
// Finalize server bootup:
await app.prepare()
})
.catch((err) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/next/compiled/conf/index.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/next/compiled/jsonwebtoken/index.js

Large diffs are not rendered by default.

15 changes: 15 additions & 0 deletions packages/next/compiled/semver/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
The ISC License

Copyright (c) Isaac Z. Schlueter and Contributors

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1 change: 1 addition & 0 deletions packages/next/compiled/semver/index.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions packages/next/compiled/semver/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"name":"semver","main":"index.js","license":"ISC"}
42 changes: 42 additions & 0 deletions packages/next/lib/get-package-version.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// issuer.endsWith(path.posix.sep) || issuer.endsWith(path.win32.sep)
import findUp from 'next/dist/compiled/find-up'
import * as path from 'path'
import { promises as fs } from 'fs'
import JSON5 from 'next/dist/compiled/json5'
import { resolveRequest } from './resolve-request'

export async function getPackageVersion({
cwd,
name,
}: {
cwd: string
name: string
}): Promise<string | null> {
const configurationPath: string | undefined = await findUp('package.json', {
cwd,
})
if (!configurationPath) {
return null
}

const content = await fs.readFile(configurationPath, 'utf-8')
const packageJson: any = JSON5.parse(content)

const { dependencies = {}, devDependencies = {} } = packageJson || {}
if (!(dependencies[name] || devDependencies[name])) {
return null
}

const cwd2 =
cwd.endsWith(path.posix.sep) || cwd.endsWith(path.win32.sep)
? cwd
: `${cwd}/`

try {
const targetPath = resolveRequest(`${name}/package.json`, cwd2)
const targetContent = await fs.readFile(targetPath, 'utf-8')
return JSON5.parse(targetContent).version ?? null
} catch {
return null
}
}
2 changes: 1 addition & 1 deletion packages/next/lib/resolve-request.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import resolve from 'next/dist/compiled/resolve/index.js'
import path from 'path'

export function resolveRequest(req: string, issuer: string) {
export function resolveRequest(req: string, issuer: string): string {
// The `resolve` package is prebuilt through ncc, which prevents
// PnP from being able to inject itself into it. To circumvent
// this, we simply use PnP directly when available.
Expand Down
2 changes: 2 additions & 0 deletions packages/next/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@
"@types/react-dom": "16.9.4",
"@types/react-is": "16.7.1",
"@types/resolve": "0.0.8",
"@types/semver": "7.3.1",
"@types/send": "0.14.4",
"@types/styled-jsx": "2.2.8",
"@types/text-table": "0.2.1",
Expand Down Expand Up @@ -200,6 +201,7 @@
"raw-body": "2.4.1",
"recast": "0.18.5",
"resolve": "1.11.0",
"semver": "7.3.2",
"send": "0.17.1",
"source-map": "0.6.1",
"string-hash": "1.1.3",
Expand Down
9 changes: 9 additions & 0 deletions packages/next/taskfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,14 @@ export async function ncc_comment_json(task, opts) {
.target('compiled/comment-json')
}

externals['semver'] = 'next/dist/compiled/semver'
export async function ncc_semver(task, opts) {
await task
.source(opts.src || relative(__dirname, require.resolve('semver')))
.ncc({ packageName: 'semver', externals })
.target('compiled/semver')
}

externals['path-to-regexp'] = 'next/dist/compiled/path-to-regexp'
export async function path_to_regexp(task, opts) {
await task
Expand Down Expand Up @@ -560,6 +568,7 @@ export async function ncc(task) {
'ncc_unistore',
'ncc_terser_webpack_plugin',
'ncc_comment_json',
'ncc_semver',
])
}

Expand Down
4 changes: 4 additions & 0 deletions packages/next/types/misc.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,10 @@ declare module 'next/dist/compiled/terser' {
import m from 'terser'
export = m
}
declare module 'next/dist/compiled/semver' {
import m from 'semver'
export = m
}
declare module 'next/dist/compiled/text-table' {
function textTable(
rows: Array<Array<{}>>,
Expand Down
1 change: 1 addition & 0 deletions test/integration/cli/old-react-dom/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
!node_modules

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions test/integration/cli/old-react-dom/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"dependencies": {
"react": "*",
"react-dom": "*"
}
}
3 changes: 3 additions & 0 deletions test/integration/cli/old-react-dom/pages/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Home() {
return <p>Hello</p>
}
1 change: 1 addition & 0 deletions test/integration/cli/old-react/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
!node_modules
1 change: 1 addition & 0 deletions test/integration/cli/old-react/node_modules/react/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions test/integration/cli/old-react/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"dependencies": {
"react": "*",
"react-dom": "*"
}
}
3 changes: 3 additions & 0 deletions test/integration/cli/old-react/pages/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Home() {
return <p>Hello</p>
}
45 changes: 43 additions & 2 deletions test/integration/cli/test/index.test.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
/* eslint-env jest */

import {
runNextCommand,
runNextCommandDev,
findPort,
killApp,
launchApp,
runNextCommand,
runNextCommandDev,
} from 'next-test-utils'
import { join } from 'path'
import pkg from 'next/package'
Expand All @@ -13,6 +14,8 @@ import http from 'http'
jest.setTimeout(1000 * 60 * 5)

const dir = join(__dirname, '..')
const dirOldReact = join(__dirname, '../old-react')
const dirOldReactDom = join(__dirname, '../old-react-dom')

describe('CLI Usage', () => {
describe('no command', () => {
Expand Down Expand Up @@ -216,6 +219,44 @@ describe('CLI Usage', () => {
})
expect(stderr).not.toContain('UnhandledPromiseRejectionWarning')
})

test('too old of react version', async () => {
const port = await findPort()

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

expect(stderr).toMatch(
'Fast Refresh is disabled in your application due to an outdated `react` version'
)
expect(stderr).not.toMatch(`react-dom`)

await killApp(instance)
})

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

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

expect(stderr).toMatch(
'Fast Refresh is disabled in your application due to an outdated `react-dom` version'
)
expect(stderr).not.toMatch('`react`')

await killApp(instance)
})
})

describe('export', () => {
Expand Down
15 changes: 11 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2903,6 +2903,13 @@
"@types/glob" "*"
"@types/node" "*"

"@types/[email protected]":
version "7.3.1"
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.1.tgz#7a9a5d595b6d873f338c867dcef64df289468cfa"
integrity sha512-ooD/FJ8EuwlDKOI6D9HWxgIgJjMg2cuziXm/42npDC8y4NjxplBUn9loewZiBNCt44450lHAU0OSb51/UqXeag==
dependencies:
"@types/node" "*"

"@types/[email protected]":
version "0.14.4"
resolved "https://registry.yarnpkg.com/@types/send/-/send-0.14.4.tgz#d70458b030305999db619a7b057f7105058bd0ff"
Expand Down Expand Up @@ -14237,15 +14244,15 @@ [email protected]:
version "7.0.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e"

[email protected], semver@^7.3.2:
version "7.3.2"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938"

semver@^6.0.0, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==

semver@^7.3.2:
version "7.3.2"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938"

semver@~5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
Expand Down

0 comments on commit bdf81a5

Please sign in to comment.