Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Minor updates for single fetch headers behavior #11377

Merged
merged 5 commits into from
Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/slow-flies-help.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@remix-run/router": minor
---

- Move `unstable_dataStrategy` from `createStaticHandler` to `staticHandler.query` so it can be request-specific for use with the `ResponseStub` approach in Remix. It's not really applicable to `queryRoute` for now since that's a singular handler call anyway so any pre-processing/post/processing could be done there manually.
- Added a new `skipLoaders` flag to `staticHandler.query` for calling only the action in Remix Single Fetch
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@
},
"filesize": {
"packages/router/dist/router.umd.min.js": {
"none": "52.4 kB"
"none": "52.8 kB"
},
"packages/react-router/dist/react-router.production.min.js": {
"none": "14.8 kB"
Expand Down
19 changes: 3 additions & 16 deletions packages/router/__tests__/ssr-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1649,11 +1649,11 @@ describe("ssr", () => {

describe("router dataStrategy", () => {
it("should support document load navigations with custom dataStrategy", async () => {
let { query } = createStaticHandler(SSR_ROUTES, {
let { query } = createStaticHandler(SSR_ROUTES);

let context = await query(createRequest("/custom"), {
unstable_dataStrategy: urlDataStrategy,
});

let context = await query(createRequest("/custom"));
expect(context).toMatchObject({
actionData: null,
loaderData: {
Expand Down Expand Up @@ -2678,18 +2678,5 @@ describe("ssr", () => {

/* eslint-enable jest/no-conditional-expect */
});

describe("router dataStrategy", () => {
it("should match routes automatically if no routeId is provided", async () => {
let { queryRoute } = createStaticHandler(SSR_ROUTES, {
unstable_dataStrategy: urlDataStrategy,
});
let data;

data = await queryRoute(createRequest("/custom"));
expect(data).toBeInstanceOf(URLSearchParams);
expect((data as URLSearchParams).get("foo")).toBe("bar");
});
});
});
});
95 changes: 80 additions & 15 deletions packages/router/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,9 @@ export interface StaticHandler {
opts?: {
loadRouteIds?: string[];
requestContext?: unknown;
skipLoaders?: boolean;
skipLoaderErrorBubbling?: boolean;
unstable_dataStrategy?: DataStrategyFunction;
}
): Promise<StaticHandlerContext | Response>;
queryRoute(
Expand Down Expand Up @@ -2926,7 +2928,6 @@ export interface CreateStaticHandlerOptions {
* @deprecated Use `mapRouteProperties` instead
*/
detectErrorBoundary?: DetectErrorBoundaryFunction;
unstable_dataStrategy?: DataStrategyFunction;
mapRouteProperties?: MapRoutePropertiesFunction;
future?: Partial<StaticHandlerFutureConfig>;
}
Expand All @@ -2942,7 +2943,6 @@ export function createStaticHandler(

let manifest: RouteManifest = {};
let basename = (opts ? opts.basename : null) || "/";
let dataStrategyImpl = opts?.unstable_dataStrategy || defaultDataStrategy;
let mapRouteProperties: MapRoutePropertiesFunction;
if (opts?.mapRouteProperties) {
mapRouteProperties = opts.mapRouteProperties;
Expand Down Expand Up @@ -2988,25 +2988,31 @@ export function createStaticHandler(
* propagate that out and return the raw Response so the HTTP server can
* return it directly.
*
* - `opts.loadRouteIds` is an optional array of routeIds if you wish to only
* run a subset of route loaders on a GET request
* - `opts.loadRouteIds` is an optional array of routeIds to run only a subset of
* loaders during a query() call
* - `opts.requestContext` is an optional server context that will be passed
* to actions/loaders in the `context` parameter
* - `opts.skipLoaderErrorBubbling` is an optional parameter that will prevent
* the bubbling of loader errors which allows single-fetch-type implementations
* the bubbling of errors which allows single-fetch-type implementations
* where the client will handle the bubbling and we may need to return data
* for the handling route
* - `opts.skipLoaders` is an optional parameter that will prevent loaders
* from running after an action
*/
async function query(
request: Request,
{
loadRouteIds,
requestContext,
skipLoaderErrorBubbling,
skipLoaders,
unstable_dataStrategy,
}: {
loadRouteIds?: string[];
requestContext?: unknown;
skipLoaderErrorBubbling?: boolean;
skipLoaders?: boolean;
unstable_dataStrategy?: DataStrategyFunction;
} = {}
): Promise<StaticHandlerContext | Response> {
let url = new URL(request.url);
Expand Down Expand Up @@ -3058,8 +3064,10 @@ export function createStaticHandler(
location,
matches,
requestContext,
unstable_dataStrategy || null,
loadRouteIds || null,
skipLoaderErrorBubbling === true,
skipLoaders === true,
null
);
if (isResponse(result)) {
Expand Down Expand Up @@ -3137,6 +3145,8 @@ export function createStaticHandler(
matches,
requestContext,
null,
null,
false,
false,
match
);
Expand Down Expand Up @@ -3174,8 +3184,10 @@ export function createStaticHandler(
location: Location,
matches: AgnosticDataRouteMatch[],
requestContext: unknown,
unstable_dataStrategy: DataStrategyFunction | null,
loadRouteIds: string[] | null,
skipLoaderErrorBubbling: boolean,
skipLoaders: boolean,
routeMatch: AgnosticDataRouteMatch | null
): Promise<Omit<StaticHandlerContext, "location" | "basename"> | Response> {
invariant(
Expand All @@ -3190,8 +3202,10 @@ export function createStaticHandler(
matches,
routeMatch || getTargetMatch(matches, location),
requestContext,
unstable_dataStrategy,
loadRouteIds,
skipLoaderErrorBubbling,
skipLoaders,
routeMatch != null
);
return result;
Expand All @@ -3201,6 +3215,7 @@ export function createStaticHandler(
request,
matches,
requestContext,
unstable_dataStrategy,
loadRouteIds,
skipLoaderErrorBubbling,
routeMatch
Expand Down Expand Up @@ -3236,8 +3251,10 @@ export function createStaticHandler(
matches: AgnosticDataRouteMatch[],
actionMatch: AgnosticDataRouteMatch,
requestContext: unknown,
unstable_dataStrategy: DataStrategyFunction | null,
loadRouteIds: string[] | null,
skipLoaderErrorBubbling: boolean,
skipLoaders: boolean,
isRouteRequest: boolean
): Promise<Omit<StaticHandlerContext, "location" | "basename"> | Response> {
let result: DataResult;
Expand All @@ -3262,7 +3279,8 @@ export function createStaticHandler(
[actionMatch],
matches,
isRouteRequest,
requestContext
requestContext,
unstable_dataStrategy
);
result = results[0];

Expand Down Expand Up @@ -3326,11 +3344,38 @@ export function createStaticHandler(
if (isErrorResult(result)) {
// Store off the pending error - we use it to determine which loaders
// to call and will commit it when we complete the navigation
let boundaryMatch = findNearestBoundary(matches, actionMatch.route.id);
let boundaryMatch = skipLoaderErrorBubbling
? actionMatch
: findNearestBoundary(matches, actionMatch.route.id);
let statusCode = isRouteErrorResponse(result.error)
? result.error.status
: result.statusCode != null
? result.statusCode
: 500;
let actionHeaders = {
...(result.headers ? { [actionMatch.route.id]: result.headers } : {}),
};

if (skipLoaders) {
return {
matches,
loaderData: {},
actionData: {},
errors: {
[boundaryMatch.route.id]: result.error,
},
statusCode,
loaderHeaders: {},
actionHeaders,
activeDeferreds: null,
};
}

let context = await loadRouteData(
loaderRequest,
matches,
requestContext,
unstable_dataStrategy,
loadRouteIds,
skipLoaderErrorBubbling,
null,
Expand All @@ -3340,20 +3385,36 @@ export function createStaticHandler(
// action status codes take precedence over loader status codes
return {
...context,
statusCode: isRouteErrorResponse(result.error)
? result.error.status
: 500,
statusCode,
actionData: null,
actionHeaders: {
...(result.headers ? { [actionMatch.route.id]: result.headers } : {}),
actionHeaders,
};
}

let actionHeaders = result.headers
? { [actionMatch.route.id]: result.headers }
: {};

if (skipLoaders) {
return {
matches,
loaderData: {},
actionData: {
[actionMatch.route.id]: result.data,
},
errors: null,
statusCode: result.statusCode || 200,
loaderHeaders: {},
actionHeaders,
activeDeferreds: null,
};
}

let context = await loadRouteData(
loaderRequest,
matches,
requestContext,
unstable_dataStrategy,
loadRouteIds,
skipLoaderErrorBubbling,
null
Expand All @@ -3376,6 +3437,7 @@ export function createStaticHandler(
request: Request,
matches: AgnosticDataRouteMatch[],
requestContext: unknown,
unstable_dataStrategy: DataStrategyFunction | null,
loadRouteIds: string[] | null,
skipLoaderErrorBubbling: boolean,
routeMatch: AgnosticDataRouteMatch | null,
Expand Down Expand Up @@ -3444,7 +3506,8 @@ export function createStaticHandler(
matchesToLoad,
matches,
isRouteRequest,
requestContext
requestContext,
unstable_dataStrategy
);

if (request.signal.aborted) {
Expand Down Expand Up @@ -3490,10 +3553,11 @@ export function createStaticHandler(
matchesToLoad: AgnosticDataRouteMatch[],
matches: AgnosticDataRouteMatch[],
isRouteRequest: boolean,
requestContext: unknown
requestContext: unknown,
unstable_dataStrategy: DataStrategyFunction | null
): Promise<DataResult[]> {
let results = await callDataStrategyImpl(
dataStrategyImpl,
unstable_dataStrategy || defaultDataStrategy,
type,
request,
matchesToLoad,
Expand Down Expand Up @@ -4188,6 +4252,7 @@ async function callDataStrategyImpl(
}),
request,
params: matches[0].params,
context: requestContext,
});

// Throw if any loadRoute implementations not called since they are what
Expand Down