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

RFC: Custom Prerendering / SSR #1108

Open
developit opened this issue Apr 3, 2020 · 2 comments
Open

RFC: Custom Prerendering / SSR #1108

developit opened this issue Apr 3, 2020 · 2 comments

Comments

@developit
Copy link
Member

developit commented Apr 3, 2020

Feature Proposal: Custom Prerendering / SSR Entry

I'd like to propose that we add support for an optional src/prerender.js (+.ts, etc) entrypoint.

When we construct the Webpack configuration for SSR/prerendering, we would detect the existence of this entry file and use it instead of src/index.js when building ssr-bundle. Detection of this file would work the same as the existing index.js entry, inferring src/ directory existence and so on.

What stays the same:

Currently, preact-cli implements prerendering automatically. We require developers export their root Component as the default export of src/index.js, and we call renderToString on it for them. This keeps things simple and has allowed us to pass an increasing amount data to the root component as props. This behavior would remain as-is for projects with no prerender.js.

What changes:

For projects that define a prerender.js, we would still require that they export their root component from src/index.js, and we will still automatically render/hydrate that component on the client. During prerendering, however, instead of importing index.js, we will import prerender.js, which is expected to export a single (async?) function. In this mode, developers must call renderToString() themselves, which means they are free to manipulate the props passed to their root component as well as the response from renderToString. The return value of the prerender() function is an object with html, body and head properties, each of which are optional strings of HTML to be inserted into the HTML template.

Example

src/index.js

import styled from 'styled-components';
const Button = styled.button`
  font-weight: bold;
`;
export default function App() {
  return <Button>Hello</Button>
}

src/prerender.js

import renderToString from 'preact-render-to-string';
import { ServerStyleSheet } from 'styled-components';
import App from './index';

export default async function prerender({ url, ...etc }) {
  const sheet = new ServerStyleSheet();
  
  const html = renderToString(sheet.collectStyles(
    <App url={url} {...etc} />
  ));

  // we'll inject <style> tag HTML into <head>
  const head = sheet.getStyleTags();

  return { html, head };
}

What does this do for CLI?

  • a clean and obvious way to avoid bundling "server" dependencies into client-side code
  • first-class SSR support for CSS-in-JS style extraction
  • first-class SSR support for Helmet-like "head manager" libraries
  • support for async and multi-call SSR solutions preact-ssr-prepass
  • better data hydration, allowing prerenderData to be extended with support for Redux, etc
  • explicit versioning for preact-render-to-string, which we currently shadow

Update: here's a mock version of prerender.js support for CLI.
It's probably broken and can only support { html } return values.

@SolarLiner
Copy link
Contributor

I don't know if this is something we can piggy-back onto this feature, but for SSR it'd be great to at least have reference to the generated client assets, or even have the generated client index.html to inject the server rendered HTML into, and send the resulting content to the client.

I haven't had success with SSR from scratch because of that, and this would facilitate the inclusion of Preact projects with features like embedded JavaScript in Spring Boot servers or using the SPA SSR feature in ASP.NET Core (or my own Django-based solution).

@benkingcode
Copy link

This would be very beneficial, I'm stuck on this currently - seems like there's no way to write 'server-only' code for the prerender... in particular to handle Styled Components

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

No branches or pull requests

3 participants