-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
feat(remix-server-runtime): pass AppLoadContext
to the server's handleRequest
function
#2045
feat(remix-server-runtime): pass AppLoadContext
to the server's handleRequest
function
#2045
Conversation
Thank you for signing the Contributor License Agreement. Let's get this merged! 🥳 |
Hmm.. not sure why it's not working for you. I setup a codesandbox that uses // server/index.js
const getLoadContext = req => ({
test: `This is from getLoadContext: ${new Date(Date.now()).toISOString()}`,
})
function handleRequest(req, res, next) {
let build = require('./build')
if (MODE !== 'production') {
purgeRequireCache()
}
return createRequestHandler({
build,
getLoadContext,
mode: MODE,
})(req, res, next)
} |
@kiliman: Thanks for the example. But this is not what this PR does. The load context is already available to all This PR adds the load context as the last parameter of the default function in |
AppLoadContext
to the server's handleRequest
functionAppLoadContext
to the server's handleRequest
function
Hmm. Sorry, I guess I misunderstood what you were doing. Ok. The But the component is also rendered on the client. Your context contains information from your adapter to be used by your loaders and actions. If there's anything in context that is needed by the component, it should be returned by the loader/action. |
The problem is that I can't rely on loaders to provide data - they're don't, for instance, in case of 404s or top-level errors. Nevertheless, we need some tenant-specific info in these cases (tenant name, logo, URL, language, color theme, and even some user-specific stuff, etc.). Since we can't pass this info via loaders in all cases, we have to partially re-implement Remix' encoding of loader data in the HTML, in our case encoding the tenant info in the topmost component into the HTML, wrapping We would like to uniformly pass the tenant-specific data in Obviously, if we can't even load the tenant info due to errors, we have to fall back to an unstyled, tenant-unspecific error. But that is extremely unlikely, as our tenant info is stored in-memory and there are not many possibilities for failures. 404s and other internal server errors, however, are likely to happen, and we have to provide a tenant-specific errors in these cases. Having said that - that's our use case. I can imagine other reasons why making the load context available everywhere on the server-side is a good idea. As a matter of fact, it is already available everywhere, except in this one specific function. This PR fixes that. |
@axel-xitaso What about getting the tenant info in the |
@MichaelDeBoey : Thanks for the suggestion. According to my tests, Update: Remix event prints an error |
Are there any plans to get this merged? If so, let me know and I'll rebase this PR onto the latest dev. Otherwise, I won't waste my time by doing so repeatedly without any indication whatsoever if this PR will ever get merged. |
Just chiming-in to say I also found myself looking for load context in This PR fixes what appears to be an oversight in the API; I cannot think of a good reason to deliberately not share the load context with Thanks @axel-habermaier! :) |
Adding my additional comment that this is important for me as well. I require an Apollo client in Personally, I cannot think of any reason not to expose the |
@axel-habermaier Could you please rebase onto latest |
@MichaelDeBoey: Done. |
Despite my earlier concerns, I will +1 this PR. I think it will be useful for cases where loaders/actions fail. This will be the last opportunity to affect the response that depends on context. |
These are odd failures in the🧪 Test / 🧪 Test OS: windows-latest for Node 14 and Node 18 which contrasts to Node 16 working. |
@mjackson Getting visibility of this since it did not make it in v1.6.0 |
Windows having that odd test failure again which was previously resolved by a force push. |
The `AppLoadContext` instance can optionally be set via the server adapter's `getLoadContext()` function. It is subsequently passed to all actions, loaders as well as the `handleDataRequest` function. It is, however, not passed to the `handleRequest` function. This PR also passes the load context to the `handleRequest` function so that the context is available everywhere in a consistent manner.
Discovered this PR while attempting to pass in Cloudflare Pages/Workers environment bindings (e.g. KV, DurableObjects) to the server's entry point. |
I've also discovered this PR while trying to pass in an instance of our logger from the express server into remix. I can get access to it just fine in actions and loaders, but, I want access to it in |
Any movement on this?... we need this as well. |
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just fixed the conflict.
I also like this idea, if the team is ok with it I propose to merge it.
PR needs to be updated after the 1.8.0 changes. |
@axel-habermaier Can you please rebase onto latest |
This PR has been automatically closed because we haven't received a response from the original author 🙈. This automation helps keep the issue tracker clean from PRs that are unactionable. Please reach out if you have more information for us! 🙂 |
😞 |
Re-opening this one as we were only a rebase away @axel-habermaier Please rebase this branch onto latest @sergiodxa I think you can create a resubmission PR as well if you want to get this one merged. |
@MichaelDeBoey: I opened this PR almost a year ago and already rebased it twice without it getting merged. Since I've completely lost all interest in Remix in the last couple of months, I won't put any more time into this PR. Sorry for that, but since the changes are trivial, someone else should easily be able to open a new PR. |
@sergiodxa If you want, please open a new PR to implement this |
Do you plan to fix this in a future release? Are someone willing to reopen this PR? Are you tempering this because of this proposal on React Router remix-run/react-router#9564 which is likely to be brought back over to Remix? In the mean time I think this is really a blocker for some users who need dependencies in their loaders or actions functions. Server side and client side. |
I was planning on recreating this PR but I’m on holiday atm. Perhaps I can get sometime soon to do it. We also need it but I’ve patched it on our side as a temp work around using npm patch package. |
@marwan38 Please bear with me since I'm not yet familiar with the Remix code base :-) But how did you patched it? I tried to apply a patch based on this PR, but I don't get how to pass the context to the // entry.server.tsx
import { PassThrough } from "stream";
import type { EntryContext } from "@remix-run/node";
import { Response } from "@remix-run/node";
import { RemixServer } from "@remix-run/react";
import isbot from "isbot";
import { renderToPipeableStream } from "react-dom/server";
const ABORT_DELAY = 5000;
export default function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext
) {
return isbot(request.headers.get("user-agent"))
? handleBotRequest(
request,
responseStatusCode,
responseHeaders,
remixContext
)
: handleBrowserRequest(
request,
responseStatusCode,
responseHeaders,
remixContext
);
}
function handleBotRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext
) {
return new Promise((resolve, reject) => {
let didError = false;
const { pipe, abort } = renderToPipeableStream(
<RemixServer context={remixContext} url={request.url} />,
{
onAllReady() {
const body = new PassThrough();
responseHeaders.set("Content-Type", "text/html");
resolve(
new Response(body, {
headers: responseHeaders,
status: didError ? 500 : responseStatusCode,
})
);
pipe(body);
},
onShellError(error: unknown) {
reject(error);
},
onError(error: unknown) {
didError = true;
console.error(error);
},
}
);
setTimeout(abort, ABORT_DELAY);
});
}
function handleBrowserRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext
) {
return new Promise((resolve, reject) => {
let didError = false;
const { pipe, abort } = renderToPipeableStream(
<RemixServer context={remixContext} url={request.url} />,
{
onShellReady() {
const body = new PassThrough();
responseHeaders.set("Content-Type", "text/html");
resolve(
new Response(body, {
headers: responseHeaders,
status: didError ? 500 : responseStatusCode,
})
);
pipe(body);
},
onShellError(err: unknown) {
reject(err);
},
onError(error: unknown) {
didError = true;
console.error(error);
},
}
);
setTimeout(abort, ABORT_DELAY);
});
} Plus, our apollo client instances are not configured exactly the same between server and client, how would you pass it to loaders context on client side only components? |
Well, in the end I think that's what I need #4123 However, the question of having different instances passed to |
I need This is what I want: export default function handleRequest(request, respondeStatusCode, respondeHeaders, remixContext, loadContext) {
Sentry.init({
dsn: loadContext.SENTRY_DSN,
})
// ...
} If there's a better way to do it though, please advise. |
The
AppLoadContext
instance can optionally be set via the server adapter'sgetLoadContext()
function. It is subsequently passed to all actions, loaders as well as thehandleDataRequest
function. It is, however, not passed to thehandleRequest
function.This PR also passes the load context to the
handleRequest
function so that the context is available everywhere in a consistent manner.