Skip to content

Commit

Permalink
Minor updates for single fetch headers behavior (#11377)
Browse files Browse the repository at this point in the history
  • Loading branch information
brophdawg11 committed Mar 26, 2024
1 parent 12afb2e commit 1058a37
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 32 deletions.
6 changes: 6 additions & 0 deletions .changeset/slow-flies-help.md
@@ -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
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
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
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

0 comments on commit 1058a37

Please sign in to comment.