diff --git a/.github/ISSUE_TEMPLATE/1.bug_report.yml b/.github/ISSUE_TEMPLATE/1.bug_report.yml index bf32ccc483252..440f9434bf332 100644 --- a/.github/ISSUE_TEMPLATE/1.bug_report.yml +++ b/.github/ISSUE_TEMPLATE/1.bug_report.yml @@ -1,6 +1,5 @@ name: Bug Report description: Create a bug report for the Next.js core -title: 'Bug Report' labels: 'template: bug' body: - type: markdown diff --git a/.github/ISSUE_TEMPLATE/2.example_bug_report.yml b/.github/ISSUE_TEMPLATE/2.example_bug_report.yml index 214c200d30fd8..8535a441bf4a7 100644 --- a/.github/ISSUE_TEMPLATE/2.example_bug_report.yml +++ b/.github/ISSUE_TEMPLATE/2.example_bug_report.yml @@ -1,6 +1,5 @@ name: Example Bug Report description: Create a bug report for the examples -title: 'Example Bug Report' labels: 'type: example,template: bug' body: - type: markdown diff --git a/.github/ISSUE_TEMPLATE/3.feature_request.yml b/.github/ISSUE_TEMPLATE/3.feature_request.yml index 44f5cffc82bd5..2655aff44d149 100644 --- a/.github/ISSUE_TEMPLATE/3.feature_request.yml +++ b/.github/ISSUE_TEMPLATE/3.feature_request.yml @@ -1,6 +1,5 @@ name: Feature Request description: Create a feature request for the Next.js core -title: 'Feature Request' labels: 'template: story' body: - type: markdown diff --git a/.github/workflows/test_react_experimental.yml b/.github/workflows/test_react_experimental.yml index 892a7dfab9985..bbfb890544d67 100644 --- a/.github/workflows/test_react_experimental.yml +++ b/.github/workflows/test_react_experimental.yml @@ -29,9 +29,9 @@ jobs: # needs: build env: NEXT_TELEMETRY_DISABLED: 1 - NEXT_PRIVATE_REACT_MODE: concurrent HEADLESS: true NEXT_PRIVATE_SKIP_SIZE_TESTS: true + NEXT_PRIVATE_REACT_ROOT: 1 strategy: fail-fast: false matrix: diff --git a/examples/api-routes-rest/README.md b/examples/api-routes-rest/README.md index 5183ca2166520..1136ed9d7efbb 100644 --- a/examples/api-routes-rest/README.md +++ b/examples/api-routes-rest/README.md @@ -18,6 +18,6 @@ npx create-next-app --example api-routes-rest api-routes-rest-app yarn create next-app --example api-routes-rest api-routes-rest-app ``` -### Deploy to Now +### Deploy to Vercel Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)). diff --git a/lerna.json b/lerna.json index 7fbf9e59b27aa..abb39f0578b1a 100644 --- a/lerna.json +++ b/lerna.json @@ -17,5 +17,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "10.1.4-canary.15" + "version": "10.1.4-canary.16" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index 73f302a8c74b9..a37c1baf7d536 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "10.1.4-canary.15", + "version": "10.1.4-canary.16", "keywords": [ "react", "next", diff --git a/packages/eslint-plugin-next/package.json b/packages/eslint-plugin-next/package.json index 90c9697347e3f..e0c857a72cc8b 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "10.1.4-canary.15", + "version": "10.1.4-canary.16", "description": "ESLint plugin for NextJS.", "main": "lib/index.js", "license": "MIT", diff --git a/packages/next-bundle-analyzer/package.json b/packages/next-bundle-analyzer/package.json index 567775a5f47e1..cda0155a9f151 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "10.1.4-canary.15", + "version": "10.1.4-canary.16", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index d9be210746a13..e542f3dcba8fb 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "10.1.4-canary.15", + "version": "10.1.4-canary.16", "license": "MIT", "dependencies": { "chalk": "4.1.0", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index fec9aa8635ea8..71fc9082dc6bc 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "10.1.4-canary.15", + "version": "10.1.4-canary.16", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index a76c08d2cf6f3..bf5a3cfafe63c 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "10.1.4-canary.15", + "version": "10.1.4-canary.16", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 1cfacb0108d8a..805a2cc572852 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "10.1.4-canary.15", + "version": "10.1.4-canary.16", "repository": { "url": "vercel/next.js", "directory": "packages/next-plugin-storybook" diff --git a/packages/next-polyfill-module/package.json b/packages/next-polyfill-module/package.json index 1e1c560c23a89..f236b03af2021 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "10.1.4-canary.15", + "version": "10.1.4-canary.16", "description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)", "main": "dist/polyfill-module.js", "license": "MIT", diff --git a/packages/next-polyfill-nomodule/package.json b/packages/next-polyfill-nomodule/package.json index 25211131ff1cf..21f1c50b3009d 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "10.1.4-canary.15", + "version": "10.1.4-canary.16", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index 9e83aa2af83c9..633a9de196375 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -1051,8 +1051,8 @@ export default async function getBaseWebpackConfig( 'process.env.__NEXT_STRICT_MODE': JSON.stringify( config.reactStrictMode ), - 'process.env.__NEXT_REACT_MODE': JSON.stringify( - config.experimental.reactMode + 'process.env.__NEXT_REACT_ROOT': JSON.stringify( + config.experimental.reactRoot ), 'process.env.__NEXT_OPTIMIZE_FONTS': JSON.stringify( config.optimizeFonts && !dev diff --git a/packages/next/client/index.tsx b/packages/next/client/index.tsx index 10e3f91699951..5abce5188dec5 100644 --- a/packages/next/client/index.tsx +++ b/packages/next/client/index.tsx @@ -494,7 +494,8 @@ export function renderError(renderErrorProps: RenderErrorProps): Promise { } let reactRoot: any = null -let shouldUseHydrate: boolean = typeof ReactDOM.hydrate === 'function' +let shouldHydrate: boolean = typeof ReactDOM.hydrate === 'function' + function renderReactElement( domEl: HTMLElement, fn: (cb: () => void) => JSX.Element @@ -504,24 +505,24 @@ function renderReactElement( performance.mark('beforeRender') } - const reactEl = fn( - shouldUseHydrate ? markHydrateComplete : markRenderComplete - ) - if (process.env.__NEXT_REACT_MODE !== 'legacy') { + const reactEl = fn(shouldHydrate ? markHydrateComplete : markRenderComplete) + if (process.env.__NEXT_REACT_ROOT) { if (!reactRoot) { - const opts = { hydrate: shouldUseHydrate } - reactRoot = - process.env.__NEXT_REACT_MODE === 'concurrent' - ? (ReactDOM as any).unstable_createRoot(domEl, opts) - : (ReactDOM as any).unstable_createBlockingRoot(domEl, opts) + const createRootName = + typeof (ReactDOM as any).unstable_createRoot === 'function' + ? 'unstable_createRoot' + : 'createRoot' + reactRoot = (ReactDOM as any)[createRootName](domEl, { + hydrate: shouldHydrate, + }) } reactRoot.render(reactEl) - shouldUseHydrate = false + shouldHydrate = false } else { // The check for `.hydrate` is there to support React alternatives like preact - if (shouldUseHydrate) { + if (shouldHydrate) { ReactDOM.hydrate(reactEl, domEl) - shouldUseHydrate = false + shouldHydrate = false } else { ReactDOM.render(reactEl, domEl) } diff --git a/packages/next/lib/typescript/writeConfigurationDefaults.ts b/packages/next/lib/typescript/writeConfigurationDefaults.ts index 61af02eca7f31..04333a8b33eae 100644 --- a/packages/next/lib/typescript/writeConfigurationDefaults.ts +++ b/packages/next/lib/typescript/writeConfigurationDefaults.ts @@ -183,7 +183,7 @@ export async function writeConfigurationDefaults( chalk.green( `We detected TypeScript in your project and reconfigured your ${chalk.bold( 'tsconfig.json' - )} file for you.` + )} file for you. Strict-mode is set to ${chalk.bold('false')} by default.` ) + '\n' ) if (suggestedActions.length) { diff --git a/packages/next/next-server/server/config-shared.ts b/packages/next/next-server/server/config-shared.ts index 1e7d88065294b..b62ccca10c727 100644 --- a/packages/next/next-server/server/config-shared.ts +++ b/packages/next/next-server/server/config-shared.ts @@ -60,6 +60,7 @@ export type NextConfig = { [key: string]: any } & { skipValidation?: boolean } turboMode: boolean + reactRoot: boolean } } @@ -104,7 +105,6 @@ export const defaultConfig: NextConfig = { plugins: false, profiling: false, sprFlushToDisk: true, - reactMode: (process.env.NEXT_PRIVATE_REACT_MODE as any) || 'legacy', workerThreads: false, pageEnv: false, optimizeImages: false, @@ -115,6 +115,7 @@ export const defaultConfig: NextConfig = { externalDir: false, serialWebpackBuild: false, turboMode: false, + reactRoot: Number(process.env.NEXT_PRIVATE_REACT_ROOT) > 0, }, future: { strictPostcssConfiguration: false, diff --git a/packages/next/next-server/server/config.ts b/packages/next/next-server/server/config.ts index b8fa8597ad803..04b5691d5b0ab 100644 --- a/packages/next/next-server/server/config.ts +++ b/packages/next/next-server/server/config.ts @@ -13,7 +13,6 @@ import { loadEnvConfig } from '@next/env' export { DomainLocales, NextConfig, normalizeConfig } from './config-shared' const targets = ['server', 'serverless', 'experimental-serverless-trace'] -const reactModes = ['legacy', 'blocking', 'concurrent'] const experimentalWarning = execOnce(() => { Log.warn(chalk.bold('You have enabled experimental feature(s).')) @@ -36,6 +35,19 @@ function assignDefaults(userConfig: { [key: string]: any }) { delete userConfig.exportTrailingSlash } + if (typeof userConfig.experimental?.reactMode !== 'undefined') { + console.warn( + chalk.yellow.bold('Warning: ') + + 'The experimental "reactMode" option has been replaced with "reactRoot". Please update your next.config.js.' + ) + if (typeof userConfig.experimental?.reactRoot === 'undefined') { + userConfig.experimental.reactRoot = ['concurrent', 'blocking'].includes( + userConfig.experimental.reactMode + ) + } + delete userConfig.experimental.reactMode + } + const config = Object.keys(userConfig).reduce<{ [key: string]: any }>( (currentConfig, key) => { const value = userConfig[key] @@ -435,17 +447,6 @@ export default async function loadConfig( : canonicalBase) || '' } - if ( - userConfig.experimental?.reactMode && - !reactModes.includes(userConfig.experimental.reactMode) - ) { - throw new Error( - `Specified React Mode is invalid. Provided: ${ - userConfig.experimental.reactMode - } should be one of ${reactModes.join(', ')}` - ) - } - if (hasNextSupport) { userConfig.target = process.env.NEXT_PRIVATE_TARGET || 'server' } diff --git a/packages/next/package.json b/packages/next/package.json index d9ebea94a9d7e..30c90e1452f0c 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "10.1.4-canary.15", + "version": "10.1.4-canary.16", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -64,10 +64,10 @@ "dependencies": { "@babel/runtime": "7.12.5", "@hapi/accept": "5.0.1", - "@next/env": "10.1.4-canary.15", - "@next/polyfill-module": "10.1.4-canary.15", - "@next/react-dev-overlay": "10.1.4-canary.15", - "@next/react-refresh-utils": "10.1.4-canary.15", + "@next/env": "10.1.4-canary.16", + "@next/polyfill-module": "10.1.4-canary.16", + "@next/react-dev-overlay": "10.1.4-canary.16", + "@next/react-refresh-utils": "10.1.4-canary.16", "@opentelemetry/api": "0.14.0", "assert": "2.0.0", "ast-types": "0.13.2", @@ -150,7 +150,7 @@ "@babel/preset-typescript": "7.12.7", "@babel/traverse": "^7.12.10", "@babel/types": "7.12.12", - "@next/polyfill-nomodule": "10.1.4-canary.15", + "@next/polyfill-nomodule": "10.1.4-canary.16", "@taskr/clear": "1.1.0", "@taskr/esnext": "1.1.0", "@taskr/watch": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index 078c7d10c3289..e729ab774a6ce 100644 --- a/packages/react-dev-overlay/package.json +++ b/packages/react-dev-overlay/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-dev-overlay", - "version": "10.1.4-canary.15", + "version": "10.1.4-canary.16", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index 19474418ddec1..6fcdcdaa616ba 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "10.1.4-canary.15", + "version": "10.1.4-canary.16", "description": "An experimental package providing utilities for React Refresh.", "repository": { "url": "vercel/next.js", diff --git a/test/integration/link-ref/pages/click-away-race-condition.js b/test/integration/link-ref/pages/click-away-race-condition.js index a5b0d51e281be..b70cdd67a35d1 100644 --- a/test/integration/link-ref/pages/click-away-race-condition.js +++ b/test/integration/link-ref/pages/click-away-race-condition.js @@ -13,9 +13,15 @@ const useClickAway = (ref, onClickAway) => { el && !el.contains(event.target) && onClickAway(event) } - document.addEventListener('click', handler) + let timeoutID = setTimeout(() => { + timeoutID = null + document.addEventListener('click', handler) + }, 0) return () => { + if (timeoutID != null) { + clearTimeout(timeoutID) + } document.removeEventListener('click', handler) } }, [onClickAway, ref])