From 42c4613b66933413c4e62d5b7cbc745dcb6fb936 Mon Sep 17 00:00:00 2001 From: Dominik Dorfmeister Date: Sat, 17 Jun 2023 14:29:12 +0200 Subject: [PATCH 01/24] chore: fix a copy-paste error --- packages/react-query-devtools/vitest.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-query-devtools/vitest.config.ts b/packages/react-query-devtools/vitest.config.ts index 70eec41e33..f61709f2fc 100644 --- a/packages/react-query-devtools/vitest.config.ts +++ b/packages/react-query-devtools/vitest.config.ts @@ -2,7 +2,7 @@ import { defineConfig } from 'vitest/config' export default defineConfig({ test: { - name: 'react-query-persist-client', + name: 'react-query-devtools', dir: './src', watch: false, setupFiles: ['test-setup.ts'], From 5777555f7f09afc157eafd55e7ea297efe7c6440 Mon Sep 17 00:00:00 2001 From: Dominik Dorfmeister Date: Sat, 17 Jun 2023 14:37:33 +0200 Subject: [PATCH 02/24] chore: bootstrap package --- .../.eslintrc.cjs | 16 ++ .../package.json | 57 ++++++ .../rollup.config.js | 12 ++ .../src/HydrationStreamProvider.tsx | 192 ++++++++++++++++++ .../src/ReactQueryStreamedHydration.tsx | 89 ++++++++ .../src/index.ts | 3 + .../test-setup.ts | 7 + .../tsconfig.eslint.json | 7 + .../tsconfig.json | 9 + .../vitest.config.ts | 13 ++ packages/react-query/package.json | 2 +- pnpm-lock.yaml | 171 +++++++++++++++- 12 files changed, 571 insertions(+), 7 deletions(-) create mode 100644 packages/react-query-next-experimental/.eslintrc.cjs create mode 100644 packages/react-query-next-experimental/package.json create mode 100644 packages/react-query-next-experimental/rollup.config.js create mode 100644 packages/react-query-next-experimental/src/HydrationStreamProvider.tsx create mode 100644 packages/react-query-next-experimental/src/ReactQueryStreamedHydration.tsx create mode 100644 packages/react-query-next-experimental/src/index.ts create mode 100644 packages/react-query-next-experimental/test-setup.ts create mode 100644 packages/react-query-next-experimental/tsconfig.eslint.json create mode 100644 packages/react-query-next-experimental/tsconfig.json create mode 100644 packages/react-query-next-experimental/vitest.config.ts diff --git a/packages/react-query-next-experimental/.eslintrc.cjs b/packages/react-query-next-experimental/.eslintrc.cjs new file mode 100644 index 0000000000..a9fa6e620d --- /dev/null +++ b/packages/react-query-next-experimental/.eslintrc.cjs @@ -0,0 +1,16 @@ +// @ts-check + +/** @type {import('eslint').Linter.Config} */ +const config = { + extends: ['plugin:react/recommended', 'plugin:react-hooks/recommended'], + parserOptions: { + tsconfigRootDir: __dirname, + project: './tsconfig.eslint.json', + }, + rules: { + 'react/jsx-key': ['error', { checkFragmentShorthand: true }], + 'react-hooks/exhaustive-deps': 'error', + }, +} + +module.exports = config diff --git a/packages/react-query-next-experimental/package.json b/packages/react-query-next-experimental/package.json new file mode 100644 index 0000000000..0b3194027d --- /dev/null +++ b/packages/react-query-next-experimental/package.json @@ -0,0 +1,57 @@ +{ + "name": "@tanstack/react-query-next-experimental", + "version": "5.0.0-alpha.67", + "description": "Hydration utils for React Query in the NextJs app directory", + "author": "tannerlinsley", + "license": "MIT", + "repository": "tanstack/query", + "homepage": "https://tanstack.com/query", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "type": "module", + "types": "build/lib/index.d.ts", + "main": "build/lib/index.legacy.cjs", + "module": "build/lib/index.legacy.js", + "exports": { + ".": { + "types": "./build/lib/index.d.ts", + "import": "./build/lib/index.js", + "require": "./build/lib/index.cjs", + "default": "./build/lib/index.cjs" + }, + "./package.json": "./package.json" + }, + "sideEffects": false, + "files": [ + "build/lib/*", + "src" + ], + "scripts": { + "clean": "rimraf ./build && rimraf ./coverage", + "test:eslint": "eslint --ext .ts,.tsx ./src", + "test:types": "tsc --noEmit", + "test:lib": "vitest run --coverage", + "test:lib:dev": "pnpm run test:lib --watch", + "test:build": "publint --strict", + "build": "pnpm build:rollup && pnpm build:types", + "build:rollup": "rollup --config rollup.config.js", + "build:types": "tsc --emitDeclarationOnly && cpy index.d.ts index.prod.d.ts --cwd=build/lib" + }, + "devDependencies": { + "@tanstack/react-query": "workspace:*", + "@types/react": "^18.2.4", + "@types/react-dom": "^18.2.4", + "next": "^13.4.6", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-error-boundary": "^3.1.4" + }, + "peerDependencies": { + "@tanstack/react-query": "workspace:*", + "next": "^13.0.0", + "react": "^18.0.0", + "react-dom": "^18.0.0" + } +} diff --git a/packages/react-query-next-experimental/rollup.config.js b/packages/react-query-next-experimental/rollup.config.js new file mode 100644 index 0000000000..149a2f25d5 --- /dev/null +++ b/packages/react-query-next-experimental/rollup.config.js @@ -0,0 +1,12 @@ +// @ts-check + +import { defineConfig } from 'rollup' +import { buildConfigs } from '../../scripts/getRollupConfig.js' + +export default defineConfig( + buildConfigs({ + name: 'react-query-next-experimental', + outputFile: 'index', + entryFile: './src/index.ts', + }), +) diff --git a/packages/react-query-next-experimental/src/HydrationStreamProvider.tsx b/packages/react-query-next-experimental/src/HydrationStreamProvider.tsx new file mode 100644 index 0000000000..82f2111c12 --- /dev/null +++ b/packages/react-query-next-experimental/src/HydrationStreamProvider.tsx @@ -0,0 +1,192 @@ +'use client' + +import { useServerInsertedHTML } from 'next/navigation' +import * as React from 'react' + +const serializedSymbol = Symbol('serialized') + +interface DataTransformer { + serialize(object: any): any + deserialize(object: any): any +} + +type Serialized = unknown & { + [serializedSymbol]: TData +} + +interface TypedDataTransformer { + serialize: (obj: TData) => Serialized + deserialize: (obj: Serialized) => TData +} + +interface HydrationStreamContext { + id: string + stream: { + /** + * **Server method** + * Push a new entry to the stream + * Will be ignored on the client + */ + push: (...shape: TShape[]) => void + } +} + +export interface HydrationStreamProviderProps { + children: React.ReactNode + /** + * Optional transformer to serialize/deserialize the data + * Example devalue, superjson et al + */ + transformer?: DataTransformer + /** + * **Client method** + * Called in the browser when new entries are received + */ + onEntries: (entries: TShape[]) => void + /** + * **Server method** + * onFlush is called on the server when the cache is flushed + */ + onFlush?: () => TShape[] +} + +export function createHydrationStreamProvider() { + const context = React.createContext>(null as any) + /** + + * 1. (Happens on server): `useServerInsertedHTML()` is called **on the server** whenever a `Suspense`-boundary completes + * - This means that we might have some new entries in the cache that needs to be flushed + * - We pass these to the client by inserting a `