Git Product home page Git Product logo

react-snap's Introduction

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 precacheAjax feature you will get faster first interaction time if your page does do AJAX requests.
  • Works with webpack 2 code splitting feature, but with caveats. See below and #46
  • Handles sourcemaps
  • Supports non-root paths (e.g. for create-react-app relative paths)

Please note: some features are experimental, but prerendering is considered stable enough.

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!

Customization

If you need to pass some options for react-snap, you can do this in the package.json, like this:

"reactSnap": {
  "inlineCss": true
}

All options are not documented yet, but you can check defaultOptions in index.js.

inlineCss

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.

precacheAjax

Experimental feature - requires improvements.

react-snap can capture all AJAX requests. It will store json request to the same domain in window.snapStore[<path>], where <path> is the path of json request.

Use precacheAjax: true to enable this feature.

✨ Recipes

See recipes for more examples.

⚠️ Caveats

Async components

Also known as code splitting, dynamic import

Webpack has a feature to split your codebase into “chunks” which are loaded on demand. Some other bundlers call them “layers”, “rollups”, or “fragments”. This feature is called “code splitting”.

Code splitting

Dynamic import is the TC39 proposal.

Async component is a technique (typically implemented as a higher order component) for loading components with dynamic import. There are a lot of solutions in this field here are some examples:

It is not a problem to render async component with react-snap, tricky part happens when prerendered React application boots and async components are not loaded yet, so React draws loading state of a component, later when component loaded react draws actual component. As the result - user sees a flash.

100%                    /----|    |----
                       /     |    |
                      /      |    |
                     /       |    |
                    /        |____|
  visual progress  /
                  /
0%  -------------/

This is a well-known problem. react-loadable and loadable-components solve this issue for SSR. But only loadable-components can solve this issue for "snapshot" setup:

import { loadComponents } from "loadable-components";
import { getState } from "loadable-components/snap";
window.snapSaveState = () => getState();

loadComponents().then(() => {
  hydrate(AppWithRouter, rootElement);
});

Redux

See: Redux Srever Rendering Section

// Grab the state from a global variable injected into the server-generated HTML
const preloadedState = window.__PRELOADED_STATE__

// Allow the passed state to be garbage-collected
delete window.__PRELOADED_STATE__

// Create Redux store with initial state
const store = createStore(counterApp, preloadedState || initialState)

// Tell react-snap how to save Redux state
window.snapSaveState = () => ({
  "__PRELOADED_STATE__": store.getState()
});

Important: as of now only basic "JSON" data types are supported e.g. Date, Set, Map, NaN won't be handled right.

TODO: use proper JS serializer (#54). See this gist for full list of alternatives.

Google Analytics, Mapbox, and other third-party requests

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

"skipThirdPartyRequests": true

WebGL

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

"headless": false

Containers and other restricted environments

Puppeteer (headless chrome) may fail due to sandboxing issues. To get around this, you may use

"puppeteerArgs": ["--no-sandbox", "--disable-setuid-sandbox"]

Read more about puppeteer troubleshooting.

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

Alternatives

react-snap's People

Contributors

badsyntax avatar diligiant avatar evenchange4 avatar lemmih avatar pushred avatar stereobooster avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.