diff --git a/.eslintrc.js b/.eslintrc.js index 35e83b0d7abcc..878dd08fda653 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -415,9 +415,7 @@ module.exports = { }, }, { - files: [ - 'packages/react-native-renderer/**/*.js', - ], + files: ['packages/react-native-renderer/**/*.js'], globals: { nativeFabricUIManager: 'readonly', }, diff --git a/packages/react-dom-bindings/src/server/ReactDOMLegacyServerStreamConfig.js b/packages/react-dom-bindings/src/server/ReactDOMLegacyServerStreamConfig.js index c682865cabafd..a568a4587fa77 100644 --- a/packages/react-dom-bindings/src/server/ReactDOMLegacyServerStreamConfig.js +++ b/packages/react-dom-bindings/src/server/ReactDOMLegacyServerStreamConfig.js @@ -76,3 +76,7 @@ export function closeWithError(destination: Destination, error: mixed): void { // $FlowFixMe[incompatible-call]: This is an Error object or the destination accepts other types. destination.destroy(error); } + +export function createFastHash(input: string): string | number { + return input; +} diff --git a/packages/react-server-dom-fb/src/ReactServerStreamConfigFB.js b/packages/react-server-dom-fb/src/ReactServerStreamConfigFB.js index 8321bdc62e551..0196b7ce1cdff 100644 --- a/packages/react-server-dom-fb/src/ReactServerStreamConfigFB.js +++ b/packages/react-server-dom-fb/src/ReactServerStreamConfigFB.js @@ -83,3 +83,7 @@ export function closeWithError(destination: Destination, error: mixed): void { destination.fatal = true; destination.error = error; } + +export function createFastHash(input: string): string | number { + return input; +} diff --git a/packages/react-server/src/ReactFizzHooks.js b/packages/react-server/src/ReactFizzHooks.js index 19256491e12d1..c80ac1e3b621a 100644 --- a/packages/react-server/src/ReactFizzHooks.js +++ b/packages/react-server/src/ReactFizzHooks.js @@ -27,6 +27,7 @@ import {getTreeId} from './ReactFizzTreeContext'; import {createThenableState, trackUsedThenable} from './ReactFizzThenable'; import {makeId, NotPendingTransition} from './ReactFizzConfig'; +import {createFastHash} from './ReactServerStreamConfig'; import { enableCache, @@ -592,11 +593,16 @@ function createPostbackFormStateKey( hookIndex: number, ): string { if (permalink !== undefined) { + // Don't bother to hash a permalink-based key since it's already short. return 'p' + permalink; } else { // Append a node to the key path that represents the form state hook. const keyPath: KeyNode = [componentKeyPath, null, hookIndex]; - return 'k' + JSON.stringify(keyPath); + // Key paths are hashed to reduce the size. It does not need to be secure, + // and it's more important that it's fast than that it's completely + // collision-free. + const keyPathHash = createFastHash(JSON.stringify(keyPath)); + return 'k' + keyPathHash; } } diff --git a/packages/react-server/src/ReactServerStreamConfigBrowser.js b/packages/react-server/src/ReactServerStreamConfigBrowser.js index c6f2ba8d7cf0a..ab1a0720e6c27 100644 --- a/packages/react-server/src/ReactServerStreamConfigBrowser.js +++ b/packages/react-server/src/ReactServerStreamConfigBrowser.js @@ -182,3 +182,7 @@ export function closeWithError(destination: Destination, error: mixed): void { destination.close(); } } + +export function createFastHash(input: string): string | number { + return input; +} diff --git a/packages/react-server/src/ReactServerStreamConfigBun.js b/packages/react-server/src/ReactServerStreamConfigBun.js index 27317f0925cd4..276c7f59e490a 100644 --- a/packages/react-server/src/ReactServerStreamConfigBun.js +++ b/packages/react-server/src/ReactServerStreamConfigBun.js @@ -7,6 +7,8 @@ * @flow */ +/* global Bun */ + type BunReadableStreamController = ReadableStreamController & { end(): mixed, write(data: Chunk | BinaryChunk): void, @@ -96,3 +98,7 @@ export function closeWithError(destination: Destination, error: mixed): void { destination.close(); } } + +export function createFastHash(input: string): string | number { + return Bun.hash(input); +} diff --git a/packages/react-server/src/ReactServerStreamConfigEdge.js b/packages/react-server/src/ReactServerStreamConfigEdge.js index b665a13706edc..a6a11d25756d2 100644 --- a/packages/react-server/src/ReactServerStreamConfigEdge.js +++ b/packages/react-server/src/ReactServerStreamConfigEdge.js @@ -182,3 +182,7 @@ export function closeWithError(destination: Destination, error: mixed): void { destination.close(); } } + +export function createFastHash(input: string): string | number { + return input; +} diff --git a/packages/react-server/src/ReactServerStreamConfigNode.js b/packages/react-server/src/ReactServerStreamConfigNode.js index d6784e3c77b3a..5d5c6b4fab3b6 100644 --- a/packages/react-server/src/ReactServerStreamConfigNode.js +++ b/packages/react-server/src/ReactServerStreamConfigNode.js @@ -10,6 +10,7 @@ import type {Writable} from 'stream'; import {TextEncoder} from 'util'; +import {createHash} from 'crypto'; interface MightBeFlushable { flush?: () => void; @@ -243,3 +244,9 @@ export function closeWithError(destination: Destination, error: mixed): void { // $FlowFixMe[incompatible-call]: This is an Error object or the destination accepts other types. destination.destroy(error); } + +export function createFastHash(input: string): string | number { + const hash = createHash('md5'); + hash.update(input); + return hash.digest('hex'); +} diff --git a/packages/react-server/src/forks/ReactServerStreamConfig.custom.js b/packages/react-server/src/forks/ReactServerStreamConfig.custom.js index 23bd4c35ddfa5..cc92a88b01e79 100644 --- a/packages/react-server/src/forks/ReactServerStreamConfig.custom.js +++ b/packages/react-server/src/forks/ReactServerStreamConfig.custom.js @@ -44,3 +44,4 @@ export const typedArrayToBinaryChunk = $$$config.typedArrayToBinaryChunk; export const clonePrecomputedChunk = $$$config.clonePrecomputedChunk; export const byteLengthOfChunk = $$$config.byteLengthOfChunk; export const byteLengthOfBinaryChunk = $$$config.byteLengthOfBinaryChunk; +export const createFastHash = $$$config.createFastHash; diff --git a/scripts/flow/environment.js b/scripts/flow/environment.js index 18ba25264138e..7f3996de04fd8 100644 --- a/scripts/flow/environment.js +++ b/scripts/flow/environment.js @@ -281,3 +281,9 @@ declare module 'node:worker_threads' { port2: MessagePort; } } + +declare var Bun: { + hash( + input: string | $TypedArray | DataView | ArrayBuffer | SharedArrayBuffer, + ): number, +}; diff --git a/scripts/rollup/bundles.js b/scripts/rollup/bundles.js index c7937ede83cd3..cd4187a34887a 100644 --- a/scripts/rollup/bundles.js +++ b/scripts/rollup/bundles.js @@ -260,7 +260,7 @@ const bundles = [ global: 'ReactDOMServer', minifyWithProdErrorCodes: false, wrapWithModuleBoundaries: false, - externals: ['react', 'util', 'async_hooks', 'react-dom'], + externals: ['react', 'util', 'crypto', 'async_hooks', 'react-dom'], }, { bundleTypes: __EXPERIMENTAL__ ? [FB_WWW_DEV, FB_WWW_PROD] : [], @@ -339,7 +339,7 @@ const bundles = [ global: 'ReactServerDOMServer', minifyWithProdErrorCodes: false, wrapWithModuleBoundaries: false, - externals: ['react', 'util', 'async_hooks', 'react-dom'], + externals: ['react', 'util', 'crypto', 'async_hooks', 'react-dom'], }, { bundleTypes: [NODE_DEV, NODE_PROD], @@ -348,7 +348,7 @@ const bundles = [ global: 'ReactServerDOMServer', minifyWithProdErrorCodes: false, wrapWithModuleBoundaries: false, - externals: ['react', 'util', 'async_hooks', 'react-dom'], + externals: ['react', 'util', 'crypto', 'async_hooks', 'react-dom'], }, { bundleTypes: [NODE_DEV, NODE_PROD], @@ -357,7 +357,7 @@ const bundles = [ global: 'ReactServerDOMServer', minifyWithProdErrorCodes: false, wrapWithModuleBoundaries: false, - externals: ['react', 'util', 'async_hooks', 'react-dom'], + externals: ['react', 'util', 'crypto', 'async_hooks', 'react-dom'], }, /******* React Server DOM Webpack Client *******/ @@ -377,7 +377,7 @@ const bundles = [ global: 'ReactServerDOMClient', minifyWithProdErrorCodes: false, wrapWithModuleBoundaries: false, - externals: ['react', 'react-dom', 'util'], + externals: ['react', 'react-dom', 'util', 'crypto'], }, { bundleTypes: [NODE_DEV, NODE_PROD], @@ -386,7 +386,7 @@ const bundles = [ global: 'ReactServerDOMClient', minifyWithProdErrorCodes: false, wrapWithModuleBoundaries: false, - externals: ['react', 'react-dom', 'util'], + externals: ['react', 'react-dom', 'util', 'crypto'], }, { bundleTypes: [NODE_DEV, NODE_PROD], @@ -439,7 +439,7 @@ const bundles = [ entry: 'react-server-dom-esm/server.node', minifyWithProdErrorCodes: false, wrapWithModuleBoundaries: false, - externals: ['react', 'util', 'async_hooks', 'react-dom'], + externals: ['react', 'util', 'crypto', 'async_hooks', 'react-dom'], }, /******* React Server DOM ESM Client *******/ @@ -457,7 +457,7 @@ const bundles = [ entry: 'react-server-dom-esm/client.node', minifyWithProdErrorCodes: false, wrapWithModuleBoundaries: false, - externals: ['react', 'react-dom', 'util'], + externals: ['react', 'react-dom', 'util', 'crypto'], }, /******* React Server DOM ESM Node.js Loader *******/ diff --git a/scripts/rollup/validate/eslintrc.cjs.js b/scripts/rollup/validate/eslintrc.cjs.js index 313f9639fb984..b3ea021a619f4 100644 --- a/scripts/rollup/validate/eslintrc.cjs.js +++ b/scripts/rollup/validate/eslintrc.cjs.js @@ -65,6 +65,8 @@ module.exports = { // Native Scheduler nativeRuntimeScheduler: 'readonly', + + Bun: 'readonly', }, parserOptions: { ecmaVersion: 2020, diff --git a/scripts/rollup/validate/eslintrc.cjs2015.js b/scripts/rollup/validate/eslintrc.cjs2015.js index dc35c98311863..435d5e5c820b6 100644 --- a/scripts/rollup/validate/eslintrc.cjs2015.js +++ b/scripts/rollup/validate/eslintrc.cjs2015.js @@ -62,6 +62,8 @@ module.exports = { // act IS_REACT_ACT_ENVIRONMENT: 'readonly', + + Bun: 'readonly', }, parserOptions: { ecmaVersion: 2015, diff --git a/scripts/rollup/validate/eslintrc.esm.js b/scripts/rollup/validate/eslintrc.esm.js index ae1846c08d7ba..11c72a68f9362 100644 --- a/scripts/rollup/validate/eslintrc.esm.js +++ b/scripts/rollup/validate/eslintrc.esm.js @@ -62,6 +62,8 @@ module.exports = { // act IS_REACT_ACT_ENVIRONMENT: 'readonly', + + Bun: 'readonly', }, parserOptions: { ecmaVersion: 2020,