Skip to content

Commit

Permalink
RSC preloading mechanism prototype
Browse files Browse the repository at this point in the history
  • Loading branch information
phryneas committed Mar 27, 2024
1 parent 0ed7998 commit 7016ab2
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 0 deletions.
27 changes: 27 additions & 0 deletions packages/client-react-streaming/src/PreloadQuery.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type { ReactNode } from "react";
import { SimulatePreloadedQuery } from "./index.cc.js";
import type { ApolloClient, QueryOptions } from "@apollo/client";
import React from "react";

export function PreloadQuery({
options,
getClient,
children,
}: {
options: QueryOptions;
getClient: () => ApolloClient<any>;
children: ReactNode;
}) {
const resultPromise = getClient().query({
...options,
// TODO: create a second Client instance only for `PreloadQuery` calls
// We want to prevent "client" data from leaking into our "RSC" cache,
// as that data should always be strictly separated.
fetchPolicy: "no-cache",
});
return (
<SimulatePreloadedQuery options={options} result={resultPromise}>
{children}
</SimulatePreloadedQuery>
);
}
58 changes: 58 additions & 0 deletions packages/client-react-streaming/src/index.cc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
"use client";

import type { FetchResult, WatchQueryOptions } from "@apollo/client/index.js";
import { useApolloClient } from "@apollo/client/index.js";
import type { ApolloClient as WrappedApolloClient } from "./DataTransportAbstraction/WrappedApolloClient.js";
import type { TransportIdentifier } from "./DataTransportAbstraction/DataTransportAbstraction.js";
import type { QueryManager } from "@apollo/client/core/QueryManager.js";
import type { ReactNode } from "react";

const handledRequests = new WeakMap<WatchQueryOptions, TransportIdentifier>();

export function SimulatePreloadedQuery({
options,
result,
children,
}: {
options: WatchQueryOptions;
result: Promise<FetchResult>;
children: ReactNode;
}) {
const client = useApolloClient() as WrappedApolloClient<any>;
if (!handledRequests.has(options)) {
const id =
`preloadedQuery:${(client["queryManager"] as QueryManager<any>).generateQueryId()}` as TransportIdentifier;
handledRequests.set(options, id);
client.onQueryStarted!({
type: "started",
id,
options,
});
result.then(
(result) => {
client.onQueryProgress!({
type: "data",
id,
result,
});
client.onQueryProgress!({
type: "complete",
id,
});
},
() => {
// TODO:
// This will restart the query in SSR **and** in the browser.
// Currently there is no way of transporting the result received in SSR to the browser.
// Layers over layers...
// Maybe instead we should just "fail" the simulated request on the SSR level
// and only have it re-attempt in the browser?
client.onQueryProgress!({
type: "error",
id,
});
}
);
}
return children;
}
1 change: 1 addition & 0 deletions packages/client-react-streaming/src/index.rsc.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { registerApolloClient } from "./registerApolloClient.js";
export * from "./index.shared.js";
export { PreloadQuery } from "./PreloadQuery.js";
15 changes: 15 additions & 0 deletions packages/client-react-streaming/tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ export default defineConfig((options) => {
"src/ManualDataTransport/index.ts",
"manual-transport.browser"
),
{
...entry("browser", "src/index.cc.ts", "index.cc"),
treeshake: false, // would remove the "use client" directive
},
];
});

Expand All @@ -74,5 +78,16 @@ const acModuleImports: Plugin = {
}
return { path: args.path, external: true };
});
// handle "client component" boundary imports
build.onResolve({ filter: /.cc.js/ }, async (args) => {
console.log(args);
if (build.initialOptions.define["TSUP_FORMAT"] === '"cjs"') {
return {
path: args.path.replace(/\/.cc.js$/, "/.cc.cjs"),
external: true,
};
}
return { path: args.path, external: true };
});
},
};

0 comments on commit 7016ab2

Please sign in to comment.