Pre-renders web app into static HTML. Uses headless chrome to pre-render. Crawls all available links starting from the root. Heavily inspired by prep and react-snapshot, but written from scratch. Uses best practices to get best loading performance.
Does not depend on React. The name is inspired by react-snapshot
and because the initial goal was to enable seamless integration with create-react-app
. Actually, it works with any technology. Considering to change the name.
- Enables SEO (google, duckduckgo...) and SMO (twitter, facebook...) for SPA.
- Works out-of-the-box with create-react-app - no code-changes required.
- Uses real browser behind the scene, so no issue with unsupported HTML5 features, like WebGL or Blobs.
- Crawls all pages starting from the root, no need to list pages by hand, like in
prep
. - With prerendered HTML and inlined critical CSS you will get fast first paint, like with critical.
- With
Preload resources
feature you will get faster first interaction time if your page does do AJAX requests. - Works with webpack 2 code splitting feature
- Handles sourcemaps
Please note: some features are experimental, but basic prerendering is considered stable enough. API is subject to change before freeze in version 1.0
.
Install:
yarn add --dev react-snap
Change package.json
:
"scripts": {
"build": "react-scripts build && react-snap"
}
Change src/index.js
(for React 16+):
import { hydrate, render } from 'react-dom';
const rootElement = document.getElementById('root');
if (rootElement.hasChildNodes()) {
hydrate(<App />, rootElement);
} else {
render(<App />, rootElement);
}
That's it!
Experimental feature - requires improvements.
react-snap
can inline critical CSS with the help of minimalcss and full CSS will be loaded in a nonblocking manner with the help of loadCss.
Use inlineCss: true
to enable this feature.
TODO: as soon as the feature will be stable it should be enabled by default. As of now <noscript>
fallback not implemented.
Experimental feature - requires improvements.
react-snap
can capture all required resources on the page and modify HTML, to instruct a browser to preload those resources.
- It will use
<link rel="preload" as="image">
for images. - it will store
json
request to the same domain inwindow.snapStore[<path>]
, where<path>
is the path of json request
Use preloadResources: true
to enable this feature.
See recipes for more examples.
You can block all third-party requests with the following config
"skipThirdPartyRequests": false
Headless chrome does not fully support WebGL, if you need render it you can use
"headless": false
If you get following error Uncaught ReferenceError: webpackJsonp is not defined
, you can use the following hack
"fixWebpackChunksIssue": true
TODO: as soon as the feature will be stable it should be enabled by default.
If you get an error in a production build, you can use sourcemaps to decode stack trace:
"sourceMaps": true
TODO: as soon as the feature will be stable it should be enabled by default.
- Fail if any page fails
- Handle minimalcss failures
- Check if
200.html
is present in target directory and exit with error if it is already there - remove
preloadResources: true
: instead change it tocacheAjaxRequests: true
- remove
preloadResources: true
, instead create separate config to preload images, and preload only visible (need to detect if images are actually visible). This would make sense if you use something like LQIP with lazy-loading for images. What about fonts? - minimalcss path URL resolution error
- Improve preconnect, dns-prefetch functionality, maybe use media queries. Example: load in small screen - capture all assets, add with a media query for the small screen, load in big screen add the rest of the assets with a media query for the big screen.
- Decide what is the optimal strategy for chunks. Use link preload or script tag with async
- Do not load assets, the same way as minimalcss does
- Check deployments to now
- Check deployments to surge
- Evaluate penthouse as alternative to minimalcss