From 0056315fafd1d43de17ce69ae14e4213890cb9c6 Mon Sep 17 00:00:00 2001 From: Lenz Weber-Tronic Date: Sun, 27 Oct 2024 06:21:14 +0000 Subject: [PATCH 1/2] bundling adjustments to create apis that can be referenced in rsc --- errors.json | 3 +- packages/toolkit/package.json | 4 + packages/toolkit/src/query/react/index.rsc.ts | 46 ++++ packages/toolkit/src/query/react/index.ts | 14 +- packages/toolkit/src/query/react/module.ts | 204 +++++++++--------- packages/toolkit/tsup.config.ts | 7 + 6 files changed, 171 insertions(+), 107 deletions(-) create mode 100644 packages/toolkit/src/query/react/index.rsc.ts diff --git a/errors.json b/errors.json index 3c3d953125..dfa9828b92 100644 --- a/errors.json +++ b/errors.json @@ -38,5 +38,6 @@ "36": "When using custom hooks for context, all hooks need to be provided: .\\nHook was either not provided or not a function.", "37": "Warning: Middleware for RTK-Query API at reducerPath \"\" has not been added to the store.\n You must add the middleware for RTK-Query to function correctly!", "38": "Cannot refetch a query that has not been started yet.", - "39": "called \\`injectEndpoints\\` to override already-existing endpointName without specifying \\`overrideExisting: true\\`" + "39": "called \\`injectEndpoints\\` to override already-existing endpointName without specifying \\`overrideExisting: true\\`", + "40": "Hooks can only be used in Client Components" } \ No newline at end of file diff --git a/packages/toolkit/package.json b/packages/toolkit/package.json index 2b765b1e6a..a3f22fa19c 100644 --- a/packages/toolkit/package.json +++ b/packages/toolkit/package.json @@ -44,6 +44,10 @@ }, "./query/react": { "types": "./dist/query/react/index.d.ts", + "react-server": { + "import": "./dist/query/react.rsc/rtk-query-react.modern.mjs", + "default": "./dist/query/react.rsc/cjs/index.js" + }, "import": "./dist/query/react/rtk-query-react.modern.mjs", "default": "./dist/query/react/cjs/index.js" } diff --git a/packages/toolkit/src/query/react/index.rsc.ts b/packages/toolkit/src/query/react/index.rsc.ts new file mode 100644 index 0000000000..d018512c46 --- /dev/null +++ b/packages/toolkit/src/query/react/index.rsc.ts @@ -0,0 +1,46 @@ +// This must remain here so that the `mangleErrors.cjs` build script +// does not have to import this into each source file it rewrites. +import { formatProdErrorMessage } from '@reduxjs/toolkit' + +import { buildCreateApi, coreModule } from '@reduxjs/toolkit/query' +import { unboundHooksModule, reactHooksModuleName } from './module' + +export * from '@reduxjs/toolkit/query' +export { ApiProvider } from './ApiProvider' + +const throwFn = () => { + throw new Error('Hooks can only be used in Client Components') +} + +const reactHooksModule = unboundHooksModule({ + hooks: { + useDispatch: throwFn, + useSelector: throwFn, + useStore: throwFn, + }, + batch: throwFn, +}) + +const createApi = /* @__PURE__ */ buildCreateApi( + coreModule(), + reactHooksModule() +) + +export type { + TypedUseMutationResult, + TypedUseQueryHookResult, + TypedUseQueryStateResult, + TypedUseQuerySubscriptionResult, + TypedLazyQueryTrigger, + TypedUseLazyQuery, + TypedUseMutation, + TypedMutationTrigger, + TypedQueryStateSelector, + TypedUseQueryState, + TypedUseQuery, + TypedUseQuerySubscription, + TypedUseLazyQuerySubscription, + TypedUseQueryStateOptions, +} from './buildHooks' +export { UNINITIALIZED_VALUE } from './constants' +export { createApi, reactHooksModule, reactHooksModuleName } diff --git a/packages/toolkit/src/query/react/index.ts b/packages/toolkit/src/query/react/index.ts index 9816a915a0..89f83b390c 100644 --- a/packages/toolkit/src/query/react/index.ts +++ b/packages/toolkit/src/query/react/index.ts @@ -1,16 +1,26 @@ // This must remain here so that the `mangleErrors.cjs` build script // does not have to import this into each source file it rewrites. import { formatProdErrorMessage } from '@reduxjs/toolkit' +import { batch, useDispatch, useSelector, useStore } from 'react-redux' import { buildCreateApi, coreModule } from '@reduxjs/toolkit/query' -import { reactHooksModule, reactHooksModuleName } from './module' +import { unboundHooksModule, reactHooksModuleName } from './module' export * from '@reduxjs/toolkit/query' export { ApiProvider } from './ApiProvider' +const reactHooksModule = unboundHooksModule({ + hooks: { + useDispatch, + useSelector, + useStore, + }, + batch, +}) + const createApi = /* @__PURE__ */ buildCreateApi( coreModule(), - reactHooksModule(), + reactHooksModule() ) export type { diff --git a/packages/toolkit/src/query/react/module.ts b/packages/toolkit/src/query/react/module.ts index 0f0816b451..365eee552d 100644 --- a/packages/toolkit/src/query/react/module.ts +++ b/packages/toolkit/src/query/react/module.ts @@ -9,12 +9,7 @@ import type { QueryDefinition, QueryKeys, } from '@reduxjs/toolkit/query' -import { - batch as rrBatch, - useDispatch as rrUseDispatch, - useSelector as rrUseSelector, - useStore as rrUseStore, -} from 'react-redux' + import { createSelector as _createSelector } from 'reselect' import { isMutationDefinition, isQueryDefinition } from '../endpointDefinitions' import { safeAssign } from '../tsHelpers' @@ -34,7 +29,7 @@ declare module '@reduxjs/toolkit/query' { // eslint-disable-next-line @typescript-eslint/no-unused-vars ReducerPath extends string, // eslint-disable-next-line @typescript-eslint/no-unused-vars - TagTypes extends string, + TagTypes extends string > { [reactHooksModuleName]: { /** @@ -50,18 +45,18 @@ declare module '@reduxjs/toolkit/query' { > ? QueryHooks : Definitions[K] extends MutationDefinition - ? MutationHooks - : never + ? MutationHooks + : never } /** * A hook that accepts a string endpoint name, and provides a callback that when called, pre-fetches the data for that endpoint. */ usePrefetch>( endpointName: EndpointName, - options?: PrefetchOptions, + options?: PrefetchOptions ): ( arg: QueryArgFrom, - options?: PrefetchOptions, + options?: PrefetchOptions ) => void } & HooksWithUniqueNames } @@ -136,103 +131,104 @@ export interface ReactHooksModuleOptions { * * @returns A module for use with `buildCreateApi` */ -export const reactHooksModule = ({ - batch = rrBatch, - hooks = { - useDispatch: rrUseDispatch, - useSelector: rrUseSelector, - useStore: rrUseStore, - }, - createSelector = _createSelector, - unstable__sideEffectsInRender = false, - ...rest -}: ReactHooksModuleOptions = {}): Module => { - if (process.env.NODE_ENV !== 'production') { - const hookNames = ['useDispatch', 'useSelector', 'useStore'] as const - let warned = false - for (const hookName of hookNames) { - // warn for old hook options - if (countObjectKeys(rest) > 0) { - if ((rest as Partial)[hookName]) { - if (!warned) { - console.warn( - 'As of RTK 2.0, the hooks now need to be specified as one object, provided under a `hooks` key:' + - '\n`reactHooksModule({ hooks: { useDispatch, useSelector, useStore } })`', - ) - warned = true +export const unboundHooksModule = + ({ + batch: defaultBatch, + hooks: defaultHooks, + }: Required>) => + ({ + batch = defaultBatch, + hooks = defaultHooks, + createSelector = _createSelector, + unstable__sideEffectsInRender = false, + ...rest + }: ReactHooksModuleOptions = {}): Module => { + if (process.env.NODE_ENV !== 'production') { + const hookNames = ['useDispatch', 'useSelector', 'useStore'] as const + let warned = false + for (const hookName of hookNames) { + // warn for old hook options + if (countObjectKeys(rest) > 0) { + if ((rest as Partial)[hookName]) { + if (!warned) { + console.warn( + 'As of RTK 2.0, the hooks now need to be specified as one object, provided under a `hooks` key:' + + '\n`reactHooksModule({ hooks: { useDispatch, useSelector, useStore } })`' + ) + warned = true + } } + // migrate + // @ts-ignore + hooks[hookName] = rest[hookName] + } + // then make sure we have them all + if (typeof hooks[hookName] !== 'function') { + throw new Error( + `When using custom hooks for context, all ${ + hookNames.length + } hooks need to be provided: ${hookNames.join( + ', ' + )}.\nHook ${hookName} was either not provided or not a function.` + ) } - // migrate - // @ts-ignore - hooks[hookName] = rest[hookName] - } - // then make sure we have them all - if (typeof hooks[hookName] !== 'function') { - throw new Error( - `When using custom hooks for context, all ${ - hookNames.length - } hooks need to be provided: ${hookNames.join( - ', ', - )}.\nHook ${hookName} was either not provided or not a function.`, - ) } } - } - return { - name: reactHooksModuleName, - init(api, { serializeQueryArgs }, context) { - const anyApi = api as any as Api< - any, - Record, - any, - any, - ReactHooksModule - > - const { buildQueryHooks, buildMutationHook, usePrefetch } = buildHooks({ - api, - moduleOptions: { - batch, - hooks, - unstable__sideEffectsInRender, - createSelector, - }, - serializeQueryArgs, - context, - }) - safeAssign(anyApi, { usePrefetch }) - safeAssign(context, { batch }) + return { + name: reactHooksModuleName, + init(api, { serializeQueryArgs }, context) { + const anyApi = api as any as Api< + any, + Record, + any, + any, + ReactHooksModule + > + const { buildQueryHooks, buildMutationHook, usePrefetch } = buildHooks({ + api, + moduleOptions: { + batch, + hooks, + unstable__sideEffectsInRender, + createSelector, + }, + serializeQueryArgs, + context, + }) + safeAssign(anyApi, { usePrefetch }) + safeAssign(context, { batch }) - return { - injectEndpoint(endpointName, definition) { - if (isQueryDefinition(definition)) { - const { - useQuery, - useLazyQuery, - useLazyQuerySubscription, - useQueryState, - useQuerySubscription, - } = buildQueryHooks(endpointName) - safeAssign(anyApi.endpoints[endpointName], { - useQuery, - useLazyQuery, - useLazyQuerySubscription, - useQueryState, - useQuerySubscription, - }) - ;(api as any)[`use${capitalize(endpointName)}Query`] = useQuery - ;(api as any)[`useLazy${capitalize(endpointName)}Query`] = - useLazyQuery - } else if (isMutationDefinition(definition)) { - const useMutation = buildMutationHook(endpointName) - safeAssign(anyApi.endpoints[endpointName], { - useMutation, - }) - ;(api as any)[`use${capitalize(endpointName)}Mutation`] = - useMutation - } - }, - } - }, + return { + injectEndpoint(endpointName, definition) { + if (isQueryDefinition(definition)) { + const { + useQuery, + useLazyQuery, + useLazyQuerySubscription, + useQueryState, + useQuerySubscription, + } = buildQueryHooks(endpointName) + safeAssign(anyApi.endpoints[endpointName], { + useQuery, + useLazyQuery, + useLazyQuerySubscription, + useQueryState, + useQuerySubscription, + }) + ;(api as any)[`use${capitalize(endpointName)}Query`] = useQuery + ;(api as any)[`useLazy${capitalize(endpointName)}Query`] = + useLazyQuery + } else if (isMutationDefinition(definition)) { + const useMutation = buildMutationHook(endpointName) + safeAssign(anyApi.endpoints[endpointName], { + useMutation, + }) + ;(api as any)[`use${capitalize(endpointName)}Mutation`] = + useMutation + } + }, + } + }, + } } -} diff --git a/packages/toolkit/tsup.config.ts b/packages/toolkit/tsup.config.ts index 48955a54e8..da09ff0aa2 100644 --- a/packages/toolkit/tsup.config.ts +++ b/packages/toolkit/tsup.config.ts @@ -115,6 +115,13 @@ const entryPoints: EntryPointOptions[] = [ extractionConfig: 'api-extractor.query-react.json', externals: ['redux', '@reduxjs/toolkit'], }, + { + prefix: 'rtk-query-react', + folder: 'query/react.rsc', + entryPoint: 'src/query/react/index.rsc.ts', + extractionConfig: 'api-extractor.query-react.json', + externals: ['redux', '@reduxjs/toolkit'], + }, ] function writeCommonJSEntry(folder: string, prefix: string) { From 8463f69763134d341d74aa40620693c8be06df52 Mon Sep 17 00:00:00 2001 From: Lenz Weber-Tronic Date: Sun, 27 Oct 2024 13:53:08 +0100 Subject: [PATCH 2/2] Update packages/toolkit/src/query/react/module.ts Co-authored-by: Arya Emami --- packages/toolkit/src/query/react/module.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/toolkit/src/query/react/module.ts b/packages/toolkit/src/query/react/module.ts index 365eee552d..b59ca72443 100644 --- a/packages/toolkit/src/query/react/module.ts +++ b/packages/toolkit/src/query/react/module.ts @@ -56,7 +56,7 @@ declare module '@reduxjs/toolkit/query' { options?: PrefetchOptions ): ( arg: QueryArgFrom, - options?: PrefetchOptions + options?: PrefetchOptions, ) => void } & HooksWithUniqueNames }