@remix-run/server-runtime
Advanced tools
Comparing version 0.0.0-experimental-935642c5 to 0.0.0-experimental-98302e22
@@ -17,11 +17,2 @@ import type { DataFunctionArgs } from "./routeModules"; | ||
} | ||
export interface StreamDocumentRequestFunction { | ||
(request: Request, responseHeaders: Headers, getRemixContext: () => Promise<Response | { | ||
context: EntryContext; | ||
status: number; | ||
}>): Promise<Response> | Response; | ||
} | ||
export interface OnLoadersCompleteCallback { | ||
(entryContext: EntryContext): void; | ||
} | ||
export interface HandleDataRequestFunction { | ||
@@ -37,3 +28,2 @@ (response: Response, args: DataFunctionArgs): Promise<Response> | Response; | ||
handleDataRequest?: HandleDataRequestFunction; | ||
streamDocument?: StreamDocumentRequestFunction; | ||
} |
/** | ||
* @remix-run/server-runtime v0.0.0-experimental-935642c5 | ||
* @remix-run/server-runtime v0.0.0-experimental-98302e22 | ||
* | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
/** | ||
* @remix-run/server-runtime v0.0.0-experimental-935642c5 | ||
* @remix-run/server-runtime v0.0.0-experimental-98302e22 | ||
* | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
/** | ||
* @remix-run/server-runtime v0.0.0-experimental-935642c5 | ||
* @remix-run/server-runtime v0.0.0-experimental-98302e22 | ||
* | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
/** | ||
* @remix-run/server-runtime v0.0.0-experimental-935642c5 | ||
* @remix-run/server-runtime v0.0.0-experimental-98302e22 | ||
* | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
/** | ||
* @remix-run/server-runtime v0.0.0-experimental-935642c5 | ||
* @remix-run/server-runtime v0.0.0-experimental-98302e22 | ||
* | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
/** | ||
* @remix-run/server-runtime v0.0.0-experimental-935642c5 | ||
* @remix-run/server-runtime v0.0.0-experimental-98302e22 | ||
* | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
/** | ||
* @remix-run/server-runtime v0.0.0-experimental-935642c5 | ||
* @remix-run/server-runtime v0.0.0-experimental-98302e22 | ||
* | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
/** | ||
* @remix-run/server-runtime v0.0.0-experimental-935642c5 | ||
* @remix-run/server-runtime v0.0.0-experimental-98302e22 | ||
* | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
/** | ||
* @remix-run/server-runtime v0.0.0-experimental-935642c5 | ||
* @remix-run/server-runtime v0.0.0-experimental-98302e22 | ||
* | ||
@@ -43,66 +43,2 @@ * Copyright (c) Remix Software Inc. | ||
function getStreamingHeaders(build, matches, routeModules, actionResponse) { | ||
let headers = new Headers(); | ||
if (actionResponse) { | ||
prependCookies(actionResponse.headers, headers); | ||
} | ||
let scripts = build.assets.entry.imports.concat(build.assets.entry.module).concat(getModuleLinkHrefs(matches, build.assets)); | ||
let assets = getPreloadLinks(matches, routeModules); | ||
let scriptLinks = dedupeHrefs(scripts).map(href => `<${href}>; rel="modulepreload"`).join(","); | ||
let assetLinks = assets.map(link => { | ||
let as = link.rel === "stylesheet" ? "style" : link.as; | ||
return `<${link.href}>; rel="preload"; as="${as}"`; | ||
}).join(","); | ||
let manifestLink = `<${build.assets.url}>; rel="preload"; as="script"`; | ||
headers.append("Link", manifestLink); | ||
headers.append("Link", scriptLinks); | ||
headers.append("Link", assetLinks); | ||
return headers; | ||
} | ||
function getModuleLinkHrefs(matches, manifest) { | ||
return dedupeHrefs(matches.map(match => { | ||
let route = manifest.routes[match.route.id]; | ||
let hrefs = [route.module]; | ||
if (route.imports) { | ||
hrefs = hrefs.concat(route.imports); | ||
} | ||
return hrefs; | ||
}).flat(1)); | ||
} | ||
function dedupeHrefs(hrefs) { | ||
return [...new Set(hrefs)]; | ||
} | ||
function getPreloadLinks(matches, routeModules) { | ||
let links = matches.map(match => { | ||
let mod = routeModules[match.route.id]; | ||
return mod.links ? mod.links() : []; | ||
}); | ||
return links.flat(1).filter(isHtmlLinkDescriptor).filter(link => link.rel === "stylesheet" || link.rel === "preload").map(({ | ||
rel, | ||
...attrs | ||
}) => { | ||
if (rel === "preload") { | ||
return { | ||
rel: "preload", | ||
...attrs | ||
}; | ||
} | ||
return { | ||
rel: "preload", | ||
as: "style", | ||
...attrs | ||
}; | ||
}); | ||
} | ||
function isHtmlLinkDescriptor(object) { | ||
return object != null && typeof object.rel === "string" && typeof object.href === "string"; | ||
} | ||
export { getDocumentHeaders, getModuleLinkHrefs, getPreloadLinks, getStreamingHeaders, isHtmlLinkDescriptor }; | ||
export { getDocumentHeaders }; |
/** | ||
* @remix-run/server-runtime v0.0.0-experimental-935642c5 | ||
* @remix-run/server-runtime v0.0.0-experimental-98302e22 | ||
* | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
/** | ||
* @remix-run/server-runtime v0.0.0-experimental-935642c5 | ||
* @remix-run/server-runtime v0.0.0-experimental-98302e22 | ||
* | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
/** | ||
* @remix-run/server-runtime v0.0.0-experimental-935642c5 | ||
* @remix-run/server-runtime v0.0.0-experimental-98302e22 | ||
* | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
/** | ||
* @remix-run/server-runtime v0.0.0-experimental-935642c5 | ||
* @remix-run/server-runtime v0.0.0-experimental-98302e22 | ||
* | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
/** | ||
* @remix-run/server-runtime v0.0.0-experimental-935642c5 | ||
* @remix-run/server-runtime v0.0.0-experimental-98302e22 | ||
* | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
/** | ||
* @remix-run/server-runtime v0.0.0-experimental-935642c5 | ||
* @remix-run/server-runtime v0.0.0-experimental-98302e22 | ||
* | ||
@@ -14,3 +14,3 @@ * Copyright (c) Remix Software Inc. | ||
import { serializeError } from './errors.js'; | ||
import { getStreamingHeaders, getDocumentHeaders } from './headers.js'; | ||
import { getDocumentHeaders } from './headers.js'; | ||
import { matchServerRoutes } from './routeMatching.js'; | ||
@@ -21,3 +21,2 @@ import { isServerMode, ServerMode } from './mode.js'; | ||
import { createServerHandoffString } from './serverHandoff.js'; | ||
import invariant from './invariant.js'; | ||
@@ -54,13 +53,2 @@ /** | ||
case "document": | ||
if (build.entry.module.streamDocument) { | ||
return streamDocumentRequest({ | ||
build, | ||
loadContext, | ||
matches, | ||
request, | ||
routes, | ||
serverMode | ||
}); | ||
} | ||
response = await renderDocumentRequest({ | ||
@@ -182,240 +170,2 @@ build, | ||
async function streamDocumentRequest({ | ||
build, | ||
loadContext, | ||
matches, | ||
request, | ||
routes, | ||
serverMode | ||
}) { | ||
let url = new URL(request.url); | ||
let appState = { | ||
trackBoundaries: true, | ||
trackCatchBoundaries: true, | ||
catchBoundaryRouteId: null, | ||
renderBoundaryRouteId: null, | ||
loaderBoundaryRouteId: null, | ||
error: undefined, | ||
catch: undefined | ||
}; | ||
if (!isValidRequestMethod(request)) { | ||
matches = null; | ||
appState.trackCatchBoundaries = false; | ||
appState.catch = { | ||
data: null, | ||
status: 405, | ||
statusText: "Method Not Allowed" | ||
}; | ||
} else if (!matches) { | ||
appState.trackCatchBoundaries = false; | ||
appState.catch = { | ||
data: null, | ||
status: 404, | ||
statusText: "Not Found" | ||
}; | ||
} | ||
let actionStatus; | ||
let actionData; | ||
let actionMatch; | ||
let actionResponse; | ||
if (matches && isActionRequest(request)) { | ||
actionMatch = getActionRequestMatch(url, matches); | ||
try { | ||
actionResponse = await callRouteAction({ | ||
loadContext, | ||
match: actionMatch, | ||
request: request | ||
}); | ||
if (isRedirectResponse(actionResponse)) { | ||
return actionResponse; | ||
} | ||
actionStatus = { | ||
status: actionResponse.status, | ||
statusText: actionResponse.statusText | ||
}; | ||
if (isCatchResponse(actionResponse)) { | ||
appState.catchBoundaryRouteId = getDeepestRouteIdWithBoundary(matches, "CatchBoundary"); | ||
appState.trackCatchBoundaries = false; | ||
appState.catch = { ...actionStatus, | ||
data: await extractData(actionResponse) | ||
}; | ||
} else { | ||
actionData = { | ||
[actionMatch.route.id]: await extractData(actionResponse) | ||
}; | ||
} | ||
} catch (error) { | ||
appState.loaderBoundaryRouteId = getDeepestRouteIdWithBoundary(matches, "ErrorBoundary"); | ||
appState.trackBoundaries = false; | ||
appState.error = await serializeError(error); | ||
if (serverMode !== ServerMode.Test) { | ||
console.error(`There was an error running the action for route ${actionMatch.route.id}`); | ||
} | ||
} | ||
} | ||
let routeModules = createEntryRouteModules(build.routes); | ||
let matchesToLoad = matches || []; | ||
if (appState.catch) { | ||
matchesToLoad = getMatchesUpToDeepestBoundary( // get rid of the action, we don't want to call it's loader either | ||
// because we'll be rendering the catch boundary, if you can get access | ||
// to the loader data in the catch boundary then how the heck is it | ||
// supposed to deal with thrown responses? | ||
matchesToLoad.slice(0, -1), "CatchBoundary"); | ||
} else if (appState.error) { | ||
matchesToLoad = getMatchesUpToDeepestBoundary( // get rid of the action, we don't want to call it's loader either | ||
// because we'll be rendering the error boundary, if you can get access | ||
// to the loader data in the error boundary then how the heck is it | ||
// supposed to deal with errors in the loader, too? | ||
matchesToLoad.slice(0, -1), "ErrorBoundary"); | ||
} | ||
async function getRemixContext() { | ||
let routeLoaderResults = await Promise.allSettled(matchesToLoad.map(match => match.route.module.loader ? callRouteLoader({ | ||
loadContext, | ||
match, | ||
request | ||
}) : Promise.resolve(undefined))); // Store the state of the action. We will use this to determine later | ||
// what catch or error boundary should be rendered under cases where | ||
// actions don't throw but loaders do, actions throw and parent loaders | ||
// also throw, etc. | ||
let actionCatch = appState.catch; | ||
let actionError = appState.error; | ||
let actionCatchBoundaryRouteId = appState.catchBoundaryRouteId; | ||
let actionLoaderBoundaryRouteId = appState.loaderBoundaryRouteId; // Reset the app error and catch state to propogate the loader states | ||
// from the results into the app state. | ||
appState.catch = undefined; | ||
appState.error = undefined; | ||
let loaderStatusCodes = []; | ||
let routeData = {}; | ||
for (let index = 0; index < matchesToLoad.length; index++) { | ||
let match = matchesToLoad[index]; | ||
let result = routeLoaderResults[index]; | ||
let error = result.status === "rejected" ? result.reason : undefined; | ||
let response = result.status === "fulfilled" ? result.value : undefined; | ||
let isRedirect = response ? isRedirectResponse(response) : false; | ||
let isCatch = response ? isCatchResponse(response) : false; // If a parent loader has already caught or error'd, bail because | ||
// we don't need any more child data. | ||
if (appState.catch || appState.error) { | ||
break; | ||
} // If there is a response and it's a redirect, do it unless there | ||
// is an action error or catch state, those action boundary states | ||
// take precedence over loader sates, this means if a loader redirects | ||
// after an action catches or errors we won't follow it, and instead | ||
// render the boundary caused by the action. | ||
if (!actionCatch && !actionError && response && isRedirect) { | ||
return response; | ||
} // Track the boundary ID's for the loaders | ||
if (match.route.module.CatchBoundary) { | ||
appState.catchBoundaryRouteId = match.route.id; | ||
} | ||
if (match.route.module.ErrorBoundary) { | ||
appState.loaderBoundaryRouteId = match.route.id; | ||
} | ||
if (error) { | ||
loaderStatusCodes.push(500); | ||
appState.trackBoundaries = false; | ||
appState.error = await serializeError(error); | ||
if (serverMode !== ServerMode.Test) { | ||
console.error(`There was an error running the data loader for route ${match.route.id}`); | ||
} | ||
break; | ||
} else if (response) { | ||
loaderStatusCodes.push(response.status); | ||
if (isCatch) { | ||
// If it's a catch response, store it in app state, and bail | ||
appState.trackCatchBoundaries = false; | ||
appState.catch = { | ||
data: await extractData(response), | ||
status: response.status, | ||
statusText: response.statusText | ||
}; | ||
break; | ||
} else { | ||
// Extract and store the loader data | ||
routeData[match.route.id] = await extractData(response); | ||
} | ||
} | ||
} // If there was not a loader catch or error state triggered reset the | ||
// boundaries as they are probably deeper in the tree if the action | ||
// initially triggered a boundary as that match would not exist in the | ||
// matches to load. | ||
if (!appState.catch) { | ||
appState.catchBoundaryRouteId = actionCatchBoundaryRouteId; | ||
} | ||
if (!appState.error) { | ||
appState.loaderBoundaryRouteId = actionLoaderBoundaryRouteId; | ||
} // If there was an action error or catch, we will reset the state to the | ||
// initial values, otherwise we will use whatever came out of the loaders. | ||
appState.catch = actionCatch || appState.catch; | ||
appState.error = actionError || appState.error; | ||
let renderableMatches = getRenderableMatches(matches, appState); | ||
if (!renderableMatches) { | ||
renderableMatches = []; | ||
let root = routes[0]; | ||
if (root && root.module.CatchBoundary) { | ||
appState.catchBoundaryRouteId = "root"; | ||
renderableMatches.push({ | ||
params: {}, | ||
pathname: "", | ||
route: routes[0] | ||
}); | ||
} | ||
} | ||
let entryMatches = createEntryMatches(renderableMatches, build.assets.routes); | ||
let serverHandoff = { | ||
actionData, | ||
appState: appState, | ||
matches: entryMatches, | ||
routeData | ||
}; | ||
let context = { ...serverHandoff, | ||
manifest: build.assets, | ||
routeModules, | ||
serverHandoffString: createServerHandoffString(serverHandoff) | ||
}; | ||
let notOkResponse = actionStatus && actionStatus.status !== 200 ? actionStatus.status : loaderStatusCodes.find(status => status !== 200); | ||
let status = appState.error ? 500 : typeof notOkResponse === "number" ? notOkResponse : appState.catch ? appState.catch.status : 200; | ||
return { | ||
context, | ||
status | ||
}; | ||
} | ||
invariant(matches, "Expected matches!"); | ||
let responseHeaders = getStreamingHeaders(build, matches, routeModules, actionResponse); | ||
invariant(build.entry.module.streamDocument, "Expected `streamDocument`"); | ||
return build.entry.module.streamDocument(request.clone(), responseHeaders, getRemixContext); | ||
} | ||
async function renderDocumentRequest({ | ||
@@ -422,0 +172,0 @@ build, |
/** | ||
* @remix-run/server-runtime v0.0.0-experimental-935642c5 | ||
* @remix-run/server-runtime v0.0.0-experimental-98302e22 | ||
* | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
/** | ||
* @remix-run/server-runtime v0.0.0-experimental-935642c5 | ||
* @remix-run/server-runtime v0.0.0-experimental-98302e22 | ||
* | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
/** | ||
* @remix-run/server-runtime v0.0.0-experimental-935642c5 | ||
* @remix-run/server-runtime v0.0.0-experimental-98302e22 | ||
* | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
/** | ||
* @remix-run/server-runtime v0.0.0-experimental-935642c5 | ||
* @remix-run/server-runtime v0.0.0-experimental-98302e22 | ||
* | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
/** | ||
* @remix-run/server-runtime v0.0.0-experimental-935642c5 | ||
* @remix-run/server-runtime v0.0.0-experimental-98302e22 | ||
* | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
import type { ServerBuild } from "./build"; | ||
import type { ServerRoute } from "./routes"; | ||
import type { RouteMatch } from "./routeMatching"; | ||
import type { AssetsManifest } from "./entry"; | ||
import type { EntryRouteModule, RouteModules } from "./routeModules"; | ||
export declare function getDocumentHeaders(build: ServerBuild, matches: RouteMatch<ServerRoute>[], routeLoaderResponses: Response[], actionResponse?: Response): Headers; | ||
export declare function getStreamingHeaders(build: ServerBuild, matches: RouteMatch<ServerRoute>[], routeModules: RouteModules<EntryRouteModule>, actionResponse?: Response): Headers; | ||
export declare function getModuleLinkHrefs(matches: RouteMatch<ServerRoute>[], manifest: AssetsManifest): string[]; | ||
export declare function getPreloadLinks(matches: RouteMatch<ServerRoute>[], routeModules: RouteModules<EntryRouteModule>): { | ||
href: string; | ||
as?: string | undefined; | ||
rel: string; | ||
}[]; | ||
export declare function isHtmlLinkDescriptor(object: any): object is { | ||
rel: string; | ||
href: string; | ||
as?: string; | ||
}; |
/** | ||
* @remix-run/server-runtime v0.0.0-experimental-935642c5 | ||
* @remix-run/server-runtime v0.0.0-experimental-98302e22 | ||
* | ||
@@ -47,70 +47,2 @@ * Copyright (c) Remix Software Inc. | ||
function getStreamingHeaders(build, matches, routeModules, actionResponse) { | ||
let headers = new Headers(); | ||
if (actionResponse) { | ||
prependCookies(actionResponse.headers, headers); | ||
} | ||
let scripts = build.assets.entry.imports.concat(build.assets.entry.module).concat(getModuleLinkHrefs(matches, build.assets)); | ||
let assets = getPreloadLinks(matches, routeModules); | ||
let scriptLinks = dedupeHrefs(scripts).map(href => `<${href}>; rel="modulepreload"`).join(","); | ||
let assetLinks = assets.map(link => { | ||
let as = link.rel === "stylesheet" ? "style" : link.as; | ||
return `<${link.href}>; rel="preload"; as="${as}"`; | ||
}).join(","); | ||
let manifestLink = `<${build.assets.url}>; rel="preload"; as="script"`; | ||
headers.append("Link", manifestLink); | ||
headers.append("Link", scriptLinks); | ||
headers.append("Link", assetLinks); | ||
return headers; | ||
} | ||
function getModuleLinkHrefs(matches, manifest) { | ||
return dedupeHrefs(matches.map(match => { | ||
let route = manifest.routes[match.route.id]; | ||
let hrefs = [route.module]; | ||
if (route.imports) { | ||
hrefs = hrefs.concat(route.imports); | ||
} | ||
return hrefs; | ||
}).flat(1)); | ||
} | ||
function dedupeHrefs(hrefs) { | ||
return [...new Set(hrefs)]; | ||
} | ||
function getPreloadLinks(matches, routeModules) { | ||
let links = matches.map(match => { | ||
let mod = routeModules[match.route.id]; | ||
return mod.links ? mod.links() : []; | ||
}); | ||
return links.flat(1).filter(isHtmlLinkDescriptor).filter(link => link.rel === "stylesheet" || link.rel === "preload").map(({ | ||
rel, | ||
...attrs | ||
}) => { | ||
if (rel === "preload") { | ||
return { | ||
rel: "preload", | ||
...attrs | ||
}; | ||
} | ||
return { | ||
rel: "preload", | ||
as: "style", | ||
...attrs | ||
}; | ||
}); | ||
} | ||
function isHtmlLinkDescriptor(object) { | ||
return object != null && typeof object.rel === "string" && typeof object.href === "string"; | ||
} | ||
exports.getDocumentHeaders = getDocumentHeaders; | ||
exports.getModuleLinkHrefs = getModuleLinkHrefs; | ||
exports.getPreloadLinks = getPreloadLinks; | ||
exports.getStreamingHeaders = getStreamingHeaders; | ||
exports.isHtmlLinkDescriptor = isHtmlLinkDescriptor; |
/** | ||
* @remix-run/server-runtime v0.0.0-experimental-935642c5 | ||
* @remix-run/server-runtime v0.0.0-experimental-98302e22 | ||
* | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
/** | ||
* @remix-run/server-runtime v0.0.0-experimental-935642c5 | ||
* @remix-run/server-runtime v0.0.0-experimental-98302e22 | ||
* | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
/** | ||
* @remix-run/server-runtime v0.0.0-experimental-935642c5 | ||
* @remix-run/server-runtime v0.0.0-experimental-98302e22 | ||
* | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
/** | ||
* @remix-run/server-runtime v0.0.0-experimental-935642c5 | ||
* @remix-run/server-runtime v0.0.0-experimental-98302e22 | ||
* | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
{ | ||
"name": "@remix-run/server-runtime", | ||
"description": "Server runtime for Remix", | ||
"version": "0.0.0-experimental-935642c5", | ||
"version": "0.0.0-experimental-98302e22", | ||
"license": "MIT", | ||
@@ -6,0 +6,0 @@ "main": "./index.js", |
/** | ||
* @remix-run/server-runtime v0.0.0-experimental-935642c5 | ||
* @remix-run/server-runtime v0.0.0-experimental-98302e22 | ||
* | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
/** | ||
* @remix-run/server-runtime v0.0.0-experimental-935642c5 | ||
* @remix-run/server-runtime v0.0.0-experimental-98302e22 | ||
* | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
/** | ||
* @remix-run/server-runtime v0.0.0-experimental-935642c5 | ||
* @remix-run/server-runtime v0.0.0-experimental-98302e22 | ||
* | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
252
server.js
/** | ||
* @remix-run/server-runtime v0.0.0-experimental-935642c5 | ||
* @remix-run/server-runtime v0.0.0-experimental-98302e22 | ||
* | ||
@@ -24,3 +24,2 @@ * Copyright (c) Remix Software Inc. | ||
var serverHandoff = require('./serverHandoff.js'); | ||
var invariant = require('./invariant.js'); | ||
@@ -57,13 +56,2 @@ /** | ||
case "document": | ||
if (build.entry.module.streamDocument) { | ||
return streamDocumentRequest({ | ||
build, | ||
loadContext, | ||
matches, | ||
request, | ||
routes: routes$1, | ||
serverMode | ||
}); | ||
} | ||
response = await renderDocumentRequest({ | ||
@@ -185,240 +173,2 @@ build, | ||
async function streamDocumentRequest({ | ||
build, | ||
loadContext, | ||
matches, | ||
request, | ||
routes, | ||
serverMode | ||
}) { | ||
let url = new URL(request.url); | ||
let appState = { | ||
trackBoundaries: true, | ||
trackCatchBoundaries: true, | ||
catchBoundaryRouteId: null, | ||
renderBoundaryRouteId: null, | ||
loaderBoundaryRouteId: null, | ||
error: undefined, | ||
catch: undefined | ||
}; | ||
if (!isValidRequestMethod(request)) { | ||
matches = null; | ||
appState.trackCatchBoundaries = false; | ||
appState.catch = { | ||
data: null, | ||
status: 405, | ||
statusText: "Method Not Allowed" | ||
}; | ||
} else if (!matches) { | ||
appState.trackCatchBoundaries = false; | ||
appState.catch = { | ||
data: null, | ||
status: 404, | ||
statusText: "Not Found" | ||
}; | ||
} | ||
let actionStatus; | ||
let actionData; | ||
let actionMatch; | ||
let actionResponse; | ||
if (matches && isActionRequest(request)) { | ||
actionMatch = getActionRequestMatch(url, matches); | ||
try { | ||
actionResponse = await data.callRouteAction({ | ||
loadContext, | ||
match: actionMatch, | ||
request: request | ||
}); | ||
if (responses.isRedirectResponse(actionResponse)) { | ||
return actionResponse; | ||
} | ||
actionStatus = { | ||
status: actionResponse.status, | ||
statusText: actionResponse.statusText | ||
}; | ||
if (responses.isCatchResponse(actionResponse)) { | ||
appState.catchBoundaryRouteId = getDeepestRouteIdWithBoundary(matches, "CatchBoundary"); | ||
appState.trackCatchBoundaries = false; | ||
appState.catch = { ...actionStatus, | ||
data: await data.extractData(actionResponse) | ||
}; | ||
} else { | ||
actionData = { | ||
[actionMatch.route.id]: await data.extractData(actionResponse) | ||
}; | ||
} | ||
} catch (error) { | ||
appState.loaderBoundaryRouteId = getDeepestRouteIdWithBoundary(matches, "ErrorBoundary"); | ||
appState.trackBoundaries = false; | ||
appState.error = await errors.serializeError(error); | ||
if (serverMode !== mode.ServerMode.Test) { | ||
console.error(`There was an error running the action for route ${actionMatch.route.id}`); | ||
} | ||
} | ||
} | ||
let routeModules = entry.createEntryRouteModules(build.routes); | ||
let matchesToLoad = matches || []; | ||
if (appState.catch) { | ||
matchesToLoad = getMatchesUpToDeepestBoundary( // get rid of the action, we don't want to call it's loader either | ||
// because we'll be rendering the catch boundary, if you can get access | ||
// to the loader data in the catch boundary then how the heck is it | ||
// supposed to deal with thrown responses? | ||
matchesToLoad.slice(0, -1), "CatchBoundary"); | ||
} else if (appState.error) { | ||
matchesToLoad = getMatchesUpToDeepestBoundary( // get rid of the action, we don't want to call it's loader either | ||
// because we'll be rendering the error boundary, if you can get access | ||
// to the loader data in the error boundary then how the heck is it | ||
// supposed to deal with errors in the loader, too? | ||
matchesToLoad.slice(0, -1), "ErrorBoundary"); | ||
} | ||
async function getRemixContext() { | ||
let routeLoaderResults = await Promise.allSettled(matchesToLoad.map(match => match.route.module.loader ? data.callRouteLoader({ | ||
loadContext, | ||
match, | ||
request | ||
}) : Promise.resolve(undefined))); // Store the state of the action. We will use this to determine later | ||
// what catch or error boundary should be rendered under cases where | ||
// actions don't throw but loaders do, actions throw and parent loaders | ||
// also throw, etc. | ||
let actionCatch = appState.catch; | ||
let actionError = appState.error; | ||
let actionCatchBoundaryRouteId = appState.catchBoundaryRouteId; | ||
let actionLoaderBoundaryRouteId = appState.loaderBoundaryRouteId; // Reset the app error and catch state to propogate the loader states | ||
// from the results into the app state. | ||
appState.catch = undefined; | ||
appState.error = undefined; | ||
let loaderStatusCodes = []; | ||
let routeData = {}; | ||
for (let index = 0; index < matchesToLoad.length; index++) { | ||
let match = matchesToLoad[index]; | ||
let result = routeLoaderResults[index]; | ||
let error = result.status === "rejected" ? result.reason : undefined; | ||
let response = result.status === "fulfilled" ? result.value : undefined; | ||
let isRedirect = response ? responses.isRedirectResponse(response) : false; | ||
let isCatch = response ? responses.isCatchResponse(response) : false; // If a parent loader has already caught or error'd, bail because | ||
// we don't need any more child data. | ||
if (appState.catch || appState.error) { | ||
break; | ||
} // If there is a response and it's a redirect, do it unless there | ||
// is an action error or catch state, those action boundary states | ||
// take precedence over loader sates, this means if a loader redirects | ||
// after an action catches or errors we won't follow it, and instead | ||
// render the boundary caused by the action. | ||
if (!actionCatch && !actionError && response && isRedirect) { | ||
return response; | ||
} // Track the boundary ID's for the loaders | ||
if (match.route.module.CatchBoundary) { | ||
appState.catchBoundaryRouteId = match.route.id; | ||
} | ||
if (match.route.module.ErrorBoundary) { | ||
appState.loaderBoundaryRouteId = match.route.id; | ||
} | ||
if (error) { | ||
loaderStatusCodes.push(500); | ||
appState.trackBoundaries = false; | ||
appState.error = await errors.serializeError(error); | ||
if (serverMode !== mode.ServerMode.Test) { | ||
console.error(`There was an error running the data loader for route ${match.route.id}`); | ||
} | ||
break; | ||
} else if (response) { | ||
loaderStatusCodes.push(response.status); | ||
if (isCatch) { | ||
// If it's a catch response, store it in app state, and bail | ||
appState.trackCatchBoundaries = false; | ||
appState.catch = { | ||
data: await data.extractData(response), | ||
status: response.status, | ||
statusText: response.statusText | ||
}; | ||
break; | ||
} else { | ||
// Extract and store the loader data | ||
routeData[match.route.id] = await data.extractData(response); | ||
} | ||
} | ||
} // If there was not a loader catch or error state triggered reset the | ||
// boundaries as they are probably deeper in the tree if the action | ||
// initially triggered a boundary as that match would not exist in the | ||
// matches to load. | ||
if (!appState.catch) { | ||
appState.catchBoundaryRouteId = actionCatchBoundaryRouteId; | ||
} | ||
if (!appState.error) { | ||
appState.loaderBoundaryRouteId = actionLoaderBoundaryRouteId; | ||
} // If there was an action error or catch, we will reset the state to the | ||
// initial values, otherwise we will use whatever came out of the loaders. | ||
appState.catch = actionCatch || appState.catch; | ||
appState.error = actionError || appState.error; | ||
let renderableMatches = getRenderableMatches(matches, appState); | ||
if (!renderableMatches) { | ||
renderableMatches = []; | ||
let root = routes[0]; | ||
if (root && root.module.CatchBoundary) { | ||
appState.catchBoundaryRouteId = "root"; | ||
renderableMatches.push({ | ||
params: {}, | ||
pathname: "", | ||
route: routes[0] | ||
}); | ||
} | ||
} | ||
let entryMatches = entry.createEntryMatches(renderableMatches, build.assets.routes); | ||
let serverHandoff$1 = { | ||
actionData, | ||
appState: appState, | ||
matches: entryMatches, | ||
routeData | ||
}; | ||
let context = { ...serverHandoff$1, | ||
manifest: build.assets, | ||
routeModules, | ||
serverHandoffString: serverHandoff.createServerHandoffString(serverHandoff$1) | ||
}; | ||
let notOkResponse = actionStatus && actionStatus.status !== 200 ? actionStatus.status : loaderStatusCodes.find(status => status !== 200); | ||
let status = appState.error ? 500 : typeof notOkResponse === "number" ? notOkResponse : appState.catch ? appState.catch.status : 200; | ||
return { | ||
context, | ||
status | ||
}; | ||
} | ||
invariant["default"](matches, "Expected matches!"); | ||
let responseHeaders = headers.getStreamingHeaders(build, matches, routeModules, actionResponse); | ||
invariant["default"](build.entry.module.streamDocument, "Expected `streamDocument`"); | ||
return build.entry.module.streamDocument(request.clone(), responseHeaders, getRemixContext); | ||
} | ||
async function renderDocumentRequest({ | ||
@@ -425,0 +175,0 @@ build, |
/** | ||
* @remix-run/server-runtime v0.0.0-experimental-935642c5 | ||
* @remix-run/server-runtime v0.0.0-experimental-98302e22 | ||
* | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
/** | ||
* @remix-run/server-runtime v0.0.0-experimental-935642c5 | ||
* @remix-run/server-runtime v0.0.0-experimental-98302e22 | ||
* | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
/** | ||
* @remix-run/server-runtime v0.0.0-experimental-935642c5 | ||
* @remix-run/server-runtime v0.0.0-experimental-98302e22 | ||
* | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
/** | ||
* @remix-run/server-runtime v0.0.0-experimental-935642c5 | ||
* @remix-run/server-runtime v0.0.0-experimental-98302e22 | ||
* | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
/** | ||
* @remix-run/server-runtime v0.0.0-experimental-935642c5 | ||
* @remix-run/server-runtime v0.0.0-experimental-98302e22 | ||
* | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
112020
61
3125