prerender-loader icon indicating copy to clipboard operation
prerender-loader copied to clipboard

Question: What do you mean by "Meaningful content".

Open gijsroge opened this issue 7 years ago • 1 comments

Sounds like a great way to optimize performance, but i'm very curious if this will serve actual content pre-rendered, or just some sort of placeholder skeleton?

Thanks for making this!

gijsroge avatar May 31 '18 07:05 gijsroge

Good question! It's actually entirely up to you. If your app does its entire initial rendering synchronously, you'll get that as the pre-rendered HTML. In a lot of cases, it would be more common to end up with a pre-rendered "App Shell", since data loading is generally not included when doing the simplest form of prerendering.

However, this is where prerender-loader gives you control over what happens: if you point it at an async function (like in the second String Prerendering example), you get to decide what to return and how long to wait for data.

Here's an example to illustrate:

<!-- src/index.html -->
<body>
  {{prerender:custom-prerender.js}}
</body>
// custom-prerender.js
import 'unfetch/polyfill';
import MyApp from './components/app';
import renderToString from 'preact-render-to-string';

export default async function prerenderWithData(params) {
  let res = await fetch('https://api.example.com/items.json');
  let items = await res.json();
  // now we have data, so we can render something meaningful:
  return renderToString(<MyApp items={items} />)
}

Note: params gets populated with whatever is passed to prerender-loader's params option


Side note: hydration

In the above example, we're prerendering using "items" data, but that data isn't available when the client code boots up in our browser. We can fix that too:

export default async function prerenderWithData() {
  let items = await (await fetch('https://api.example.com/items.json')).json();
  let script = document.createElement('script');
  script.textContent = `window.DATA = ${JSON.stringify(items)}`;
  document.body.appendChild(script);
  return renderToString(<MyApp items={items} />)
}

// now all we have to do is add a check in our MyApp component (or wherever "items" was being used) for window.DATA:
const MyApp = ({ items = window.DATA }) => (
  <ul>{items.map( item => <li>{item}</li> )}</ul>
)

developit avatar May 31 '18 20:05 developit