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

Provide full request object to renderer #802

Closed
Jefftopia opened this issue Dec 15, 2023 · 7 comments · Fixed by #806
Closed

Provide full request object to renderer #802

Jefftopia opened this issue Dec 15, 2023 · 7 comments · Fixed by #806

Comments

@Jefftopia
Copy link
Contributor

To provide cookies to your Angular app, it is sometimes necessary to provide it to your Angular from the server entrypoint prior to the Angular app taking over. Cookies, for example, are sometimes omitted due to Angular's xhr2's strictCookies setting.

I have observed this both in my local analogjs app and pure Angular apps with ssr and express. To avoid this in an express-angular project, I simply provide the REQUEST to my app using the nguniversal token:

  server.get('*', (req, res, next) => {
    const { protocol, originalUrl, baseUrl, headers } = req;
    commonEngine
      .render({
        bootstrap,
        documentFilePath: indexHtml,
        url: `${protocol}://${headers.host}${originalUrl}`,
        publicPath: browserDistFolder,
        providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }, { provide: REQUEST, useValue: req } ], // <--- provided here
      })
      .then((html) => res.send(html))
      .catch((err) => next(err));
  });

Analog does not yet provide a way to do this. The request object handled by a load hook, for example, which is really just a route resolver, is already sanitized by the framework; it is not a raw request and hence, in my case, lacked cookies.

I noticed that modifying the lines highlighted below gave me the full request with the cookies I needed:

https://github.com/analogjs/analog/blob/main/packages/vite-plugin-nitro/src/lib/runtime/renderer.js#L14-L15

const result = await entryServer(req.originalUrl, template);

I am looking for either advice on how to make a backwards compatible PR that will work with different deployments, or from an existing contributor to take point on a solution. This is unfortunately a blocker for me :-(

@brandonroberts
Copy link
Member

Thanks @Jefftopia. This isn't currently officially supported. As a workaround, you can define a custom renderer and server entry point.

I put together a repo below that shows the changes needed in a commit.

https://github.com/brandonroberts/analog-server-request

It's not supported in dev mode unless you patch this file for the Vite dev server to pass the request/response the same way to the renderer.

https://github.com/analogjs/analog/blob/main/packages/vite-plugin-nitro/src/lib/plugins/dev-server-plugin.ts#L46

@Jefftopia
Copy link
Contributor Author

Thank you @brandonroberts. If I were to create a PR to pass the full object, what are some test cases you would want covered?

@brandonroberts
Copy link
Member

I think it would be enough to add a page to the analog-app and E2E test that handles injecting and use a request/response in client code.

We don't have any InjectionTokens defined for those either, so those could be defined in the analog-app for now. I'm not sure provided easy access to injecting request/response into client code is the long term goal, but it is useful in some cases.

@Jefftopia
Copy link
Contributor Author

Jefftopia commented Dec 15, 2023

Thanks. I agree that it is not ideal to have these in client code, particularly the response. Two observations:

  1. I only need the request. Does it makes sense to have both for completeness or should I focus on the request only?
  2. I only need these on the server; on the client, I have access to all of the cookies from the document (and credentials: 'include' / withCredentials: true behaves in a more expected way there). That said, is there a straightforward way in Angular to scope the provider to the server only?

@brandonroberts
Copy link
Member

  1. I think both should be provided
  2. You would only provide them in the main.server.ts with the platformProviders. When you try to access them in the client app, they should be injected as optional because they will be undefined.

You can't scope it to the server only without using the isPlatformServer() checks if you want to use Angular patterns.
Vite also has an import.meta.env.SSR you could wrap the code in that causes it to get tree-shaken in the client build.

@Jefftopia
Copy link
Contributor Author

Jefftopia commented Dec 18, 2023

@brandonroberts Working on a PR now, but it looks like the event passed to export default eventHandler in renderer.js only has the equivalent of a Request object, and no response object.

  1. Am I missing a step?
  2. If not, do you want to revisit including the Response?
  3. Or just have the Response be undefined when running deployed?

Edit: disregard, found them in the h3 docs.

Jefftopia added a commit to Jefftopia/analog that referenced this issue Dec 18, 2023
PR adds full req and res object from h3 to the analog event handler for  app rendering

closes analogjs#802
Jefftopia added a commit to Jefftopia/analog that referenced this issue Dec 19, 2023
@brandonroberts
Copy link
Member

This is included in the 0.2.29 release

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants