From 3211b3f6724f6b56c50f0eecbc67eb6fb4213195 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Sun, 25 Sep 2022 21:35:05 +0200 Subject: [PATCH] Upgrade react@experimental (#40885) --- package.json | 4 +- .../client/components/hooks-server-context.ts | 12 +- .../components/layout-router.client.tsx | 2 +- packages/next/client/components/redirect.ts | 2 +- ...bpack-writer.browser.development.server.js | 122 ++++++++++++++---- ...ck-writer.browser.production.min.server.js | 71 +++++----- .../react-server-dom-webpack.development.js | 19 ++- ...react-server-dom-webpack.production.min.js | 4 +- packages/next/export/worker.ts | 9 +- packages/next/package.json | 2 +- packages/next/server/app-render.tsx | 16 +-- pnpm-lock.yaml | 34 ++--- 12 files changed, 182 insertions(+), 115 deletions(-) diff --git a/package.json b/package.json index 5a7c7195367fb..1a8c8ec12300f 100644 --- a/package.json +++ b/package.json @@ -181,8 +181,8 @@ "react-17": "npm:react@17.0.2", "react-dom": "18.2.0", "react-dom-17": "npm:react-dom@17.0.2", - "react-dom-exp": "npm:react-dom@0.0.0-experimental-8951c5fc9-20220915", - "react-exp": "npm:react@0.0.0-experimental-8951c5fc9-20220915", + "react-dom-exp": "npm:react-dom@0.0.0-experimental-cb5084d1c-20220924", + "react-exp": "npm:react@0.0.0-experimental-cb5084d1c-20220924", "react-ssr-prepass": "1.0.8", "react-virtualized": "9.22.3", "relay-compiler": "13.0.2", diff --git a/packages/next/client/components/hooks-server-context.ts b/packages/next/client/components/hooks-server-context.ts index 4fe4b21b1fff0..37c0ac9f2ad3a 100644 --- a/packages/next/client/components/hooks-server-context.ts +++ b/packages/next/client/components/hooks-server-context.ts @@ -1,14 +1,8 @@ -// @ts-expect-error createServerContext exists on experimental channel -import { createServerContext } from 'react' - -// createServerContext exists in react@experimental + react-dom@experimental -if (typeof createServerContext === 'undefined') { - throw new Error( - '"app" directory requires React.createServerContext which is not available in the version of React you are using. Please update to react@experimental and react-dom@experimental.' - ) -} +export const DYNAMIC_ERROR_CODE = 'DYNAMIC_SERVER_USAGE' export class DynamicServerError extends Error { + digest: typeof DYNAMIC_ERROR_CODE = DYNAMIC_ERROR_CODE + constructor(type: string) { super(`Dynamic server usage: ${type}`) } diff --git a/packages/next/client/components/layout-router.client.tsx b/packages/next/client/components/layout-router.client.tsx index 9ebd2a3cb6f57..bbe5e3d5c2470 100644 --- a/packages/next/client/components/layout-router.client.tsx +++ b/packages/next/client/components/layout-router.client.tsx @@ -309,7 +309,7 @@ class RedirectErrorBoundary extends React.Component< } static getDerivedStateFromError(error: any) { - if (error.code === 'NEXT_REDIRECT') { + if (error.digest === 'NEXT_REDIRECT') { return { redirect: error.url } } // Re-throw if error is not for 404 diff --git a/packages/next/client/components/redirect.ts b/packages/next/client/components/redirect.ts index a5d9bd9294171..396bd7655ba19 100644 --- a/packages/next/client/components/redirect.ts +++ b/packages/next/client/components/redirect.ts @@ -4,6 +4,6 @@ export function redirect(url: string) { // eslint-disable-next-line no-throw-literal const error = new Error(REDIRECT_ERROR_CODE) ;(error as any).url = url - ;(error as any).code = REDIRECT_ERROR_CODE + ;(error as any).digest = REDIRECT_ERROR_CODE throw error } diff --git a/packages/next/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-writer.browser.development.server.js b/packages/next/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-writer.browser.development.server.js index d059e1b5573b5..b441b58334446 100644 --- a/packages/next/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-writer.browser.development.server.js +++ b/packages/next/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-writer.browser.development.server.js @@ -153,8 +153,22 @@ function serializeRowHeader(tag, id) { return tag + id.toString(16) + ':'; } -function processErrorChunk(request, id, message, stack) { +function processErrorChunkProd(request, id, digest) { + { + // These errors should never make it into a build so we don't need to encode them in codes.json + // eslint-disable-next-line react-internal/prod-error-codes + throw new Error('processErrorChunkProd should never be called while in development mode. Use processErrorChunkDev instead. This is a bug in React.'); + } + + var errorInfo = { + digest: digest + }; + var row = serializeRowHeader('E', id) + stringify(errorInfo) + '\n'; +} +function processErrorChunkDev(request, id, digest, message, stack) { + var errorInfo = { + digest: digest, message: message, stack: stack }; @@ -1388,7 +1402,16 @@ function serializeModuleReference(request, parent, key, moduleReference) { } catch (x) { request.pendingChunks++; var errorId = request.nextChunkId++; - emitErrorChunk(request, errorId, x); + var digest = logRecoverableError(request, x); + + { + var _getErrorMessageAndSt = getErrorMessageAndStackDev(x), + message = _getErrorMessageAndSt.message, + stack = _getErrorMessageAndSt.stack; + + emitErrorChunkDev(request, errorId, digest, message, stack); + } + return serializeByValueID(errorId); } } @@ -1633,7 +1656,16 @@ function resolveModelToJSON(request, parent, key, value) { request.pendingChunks++; var errorId = request.nextChunkId++; - emitErrorChunk(request, errorId, x); + var digest = logRecoverableError(request, x); + + { + var _getErrorMessageAndSt2 = getErrorMessageAndStackDev(x), + message = _getErrorMessageAndSt2.message, + stack = _getErrorMessageAndSt2.stack; + + emitErrorChunkDev(request, errorId, digest, message, stack); + } + return serializeByRefID(errorId); } } @@ -1744,7 +1776,39 @@ function resolveModelToJSON(request, parent, key, value) { function logRecoverableError(request, error) { var onError = request.onError; - onError(error); + var errorDigest = onError(error); + + if (errorDigest != null && typeof errorDigest !== 'string') { + // eslint-disable-next-line react-internal/prod-error-codes + throw new Error("onError returned something with a type other than \"string\". onError should return a string and may return null or undefined but must not return anything else. It received something of type \"" + typeof errorDigest + "\" instead"); + } + + return errorDigest || ''; +} + +function getErrorMessageAndStackDev(error) { + { + var message; + var stack = ''; + + try { + if (error instanceof Error) { + // eslint-disable-next-line react-internal/safe-string-coercion + message = String(error.message); // eslint-disable-next-line react-internal/safe-string-coercion + + stack = String(error.stack); + } else { + message = 'Error: ' + error; + } + } catch (x) { + message = 'An error occurred but serializing the error message failed.'; + } + + return { + message: message, + stack: stack + }; + } } function fatalError(request, error) { @@ -1758,27 +1822,13 @@ function fatalError(request, error) { } } -function emitErrorChunk(request, id, error) { - // TODO: We should not leak error messages to the client in prod. - // Give this an error code instead and log on the server. - // We can serialize the error in DEV as a convenience. - var message; - var stack = ''; - - try { - if (error instanceof Error) { - // eslint-disable-next-line react-internal/safe-string-coercion - message = String(error.message); // eslint-disable-next-line react-internal/safe-string-coercion - - stack = String(error.stack); - } else { - message = 'Error: ' + error; - } - } catch (x) { - message = 'An error occurred but serializing the error message failed.'; - } +function emitErrorChunkProd(request, id, digest) { + var processedChunk = processErrorChunkProd(request, id, digest); + request.completedErrorChunks.push(processedChunk); +} - var processedChunk = processErrorChunk(request, id, message, stack); +function emitErrorChunkDev(request, id, digest, message, stack) { + var processedChunk = processErrorChunkDev(request, id, digest, message, stack); request.completedErrorChunks.push(processedChunk); } @@ -1850,9 +1900,15 @@ function retryTask(request, task) { } else { request.abortableTasks.delete(task); task.status = ERRORED; - logRecoverableError(request, x); // This errored, we need to serialize this error to the + var digest = logRecoverableError(request, x); + + { + var _getErrorMessageAndSt3 = getErrorMessageAndStackDev(x), + message = _getErrorMessageAndSt3.message, + stack = _getErrorMessageAndSt3.stack; - emitErrorChunk(request, task.id, x); + emitErrorChunkDev(request, task.id, digest, message, stack); + } } } } @@ -2005,10 +2061,20 @@ function abort(request, reason) { // to that row from every row that's still remaining. var _error = reason === undefined ? new Error('The render was aborted by the server without a reason.') : reason; - logRecoverableError(request, _error); + var digest = logRecoverableError(request, _error); request.pendingChunks++; var errorId = request.nextChunkId++; - emitErrorChunk(request, errorId, _error); + + if (true) { + var _getErrorMessageAndSt4 = getErrorMessageAndStackDev(_error), + message = _getErrorMessageAndSt4.message, + stack = _getErrorMessageAndSt4.stack; + + emitErrorChunkDev(request, errorId, digest, message, stack); + } else { + emitErrorChunkProd(request, errorId, digest); + } + abortableTasks.forEach(function (task) { return abortTask(task, request, errorId); }); diff --git a/packages/next/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-writer.browser.production.min.server.js b/packages/next/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-writer.browser.production.min.server.js index e1e75332dacc9..02a92dc7b7254 100644 --- a/packages/next/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-writer.browser.production.min.server.js +++ b/packages/next/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-writer.browser.production.min.server.js @@ -7,44 +7,45 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ -'use strict';var e=require("react"),l=null,m=0;function n(a,c){if(0!==c.length)if(512