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

Allow supplying a custom pageContextInit when using the Vite CLI #452

Closed
AaronBeaudoin opened this issue Sep 14, 2022 · 7 comments
Closed
Labels
enhancement ✨ New feature or request

Comments

@AaronBeaudoin
Copy link
Contributor

AaronBeaudoin commented Sep 14, 2022

Description

I think it's overkill to require users to roll their own entire Express server just to do small stuff like pass a custom fetch implementation. I would love to see a new option on the VPS plugin config like this:

import fetch from 'node-fetch'

ssr({
  // Other options, like `prerender: true`...

  pageContextInit(req) {
    const userAgent = req.headers['user-agent']
    const pageContextInit = { urlOriginal: req.originalUrl || req.url, userAgent, fetch }
    return pageContextInit
  }
})

It takes the Vite dev server req as it's only parameter and must return an object to be used as pageContextInit for renderPage during development when using the Vite CLI.

Hopefully this would be pretty easy to add. I'd like to use this for the project I'm building on Cloudflare Workers. In my case, I'm actually creating my own extended fetch implementation that additionally allows you to call it with a string like /fn/whatever without an origin, in which case my worker just "calls itself" internally to save a round-trip to the internet. I don't want to clutter my project with an entirely custom server, though, and I want to keep my dependency list as lean as possible, since I intend to share it as a template for other people to use and I want it to be super clean.

@AaronBeaudoin AaronBeaudoin added the enhancement ✨ New feature or request label Sep 14, 2022
@brillout
Copy link
Member

I agree and it's on the radar.

The plan is to be able to use vite-plugin-ssr with HatTip in a straightforward and easy way.

@AaronBeaudoin
Copy link
Contributor Author

AaronBeaudoin commented Sep 20, 2022

I actually found a fairly clean approach to achieve this by dipping my toes into custom Vite plugins.

For anyone else stumbling across this issue trying to do the same thing—all you need to do is make a minimal Vite plugin like this and put it right before vite-plugin-ssr in your vite.config.js plugin list:

{
  name: "call-it-whatever-you-want",
  configureServer(server) {
    return () => {
      server.middlewares.use(async (request, response, next) => {
        if (response.headersSent) return next();
        if (!(request.originalUrl || request.url)) return next();
        
        const initialPageContext = {
          urlOriginal: request.originalUrl || request.url,
          userAgent: request.headers["user-agent"],

          // Add whatever additional data you want.
          test: "WOWZERS"
        };

        const pageContext = await renderPage(initialPageContext);
        if (!pageContext.httpResponse) return next();

        response.setHeader("Content-Type", pageContext.httpResponse.contentType);
        response.writeHead(pageContext.httpResponse.statusCode);
        pageContext.httpResponse.pipe(response);
      });
    };
  }
}
  • This is very similar to how you integrate vite-plugin-ssr into any arbitrary deployment platform.
  • It just mimics the code in the original vite-plugin-ssr middleware you can see here.

The only thing that is weird about this is that if if (!pageContext.httpResponse) return next(); is hit (which as far I know should never happen since vite-plugin-ssr falls back to an error page) then the original middleware will run. But even if it does, it should be working with the same routes, so I'd expect it to pass through via next() in exactly the same way.

I just tried this solution and so far I'm not seeing any issues with it. I'll definitely follow-up on this if I do.

@samuelstroschein
Copy link
Contributor

Wouldn't it be better to expose the request to the server renderer(s) instead of defining PageContextInit in the vite config?

I fear that defining custom PageContext in the Vite config leads to additional complexity to understand how vite-plugin-ssr works/how an implementation of VPS works. Defining custom PageContext in the _default renderers is straightforward. Whether a PageContextInit is defined in the vite config or the PageContext is supplemented in a _renderer should make no difference, right?

@brillout
Copy link
Member

I agree. One goal of the new VPS design is to move all options defined in vite.config.js to _define.js.

A new hook _define.js#onRequest would do the trick. (Or onRequestVite/onRequestHattip for better TS support.)

@brillout
Copy link
Member

Closing for lack of interest. (I actually do think that some hook is missing here. But I'm waiting for enough users to complain and/or a strong use case for it.)

@brillout brillout closed this as not planned Won't fix, can't repro, duplicate, stale May 31, 2023
@pdanpdan
Copy link

pdanpdan commented Jan 2, 2024

I just hit this problem.
I need to access some headers ('accept-language', 'sec-ch-*') and cookies in +onRenderHtml to decide what initial view to render for the client.
It works well with a custom express server, but I think it would require a full replacement of the Vike middleware entry in vite.config in order to work.

A custom pageContextInit with access to request would solve this elegantly.

@brillout
Copy link
Member

brillout commented Jan 2, 2024

@pdanpdan I ain't sure I understand your point. If you access headers then you, de facto, are using a server. So AFAICT you can simply access the headers at your Vike middleware as described in the docs. Feel free to create a new GitHub discussion to elaborate.

A custom pageContextInit with access to request would solve this elegantly.

You can actually already achieve this setting pageContextInit.headers at your Vike middleware, while using one global onBeforeRender() hook and multiple per-page data() hooks for data fetching.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement ✨ New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants