Skip to content

A zero-configuration static pre-renderer for Single Page Applications

License

Notifications You must be signed in to change notification settings

diligiant/react-snap

 
 

Repository files navigation

react-snap npm npm Hacker News

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.

Features

  • 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.

Basic usage with create-react-app

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!

Inline css

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.

Preload resources

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 in window.snapStore[<path>], where <path> is the path of json request

Use preloadResources: true to enable this feature.

Recipes

See recipes for more examples.

Caveats

Google Analytics, Mapbox, and other third-party requests

You can block all third-party requests with the following config

"skipThirdPartyRequests": false

WebGL

Headless chrome does not fully support WebGL, if you need render it you can use

"headless": false

Webpack 2+ and dynamic import

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.

Error stack trace in production build

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.

TODO

  • 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 to cacheAjaxRequests: 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

About

A zero-configuration static pre-renderer for Single Page Applications

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • JavaScript 100.0%