React ESI: Blazing-fast Server-Side Rendering for React and Next.js

Overview

React ESI: Blazing-fast Server-Side Rendering for React and Next.js

Build Status Coverage Status npm version MIT Licence

React ESI is a super powerful cache library for vanilla React and Next.js applications, that can make highly dynamic applications as fast as static sites. It provides a straightforward way to boost your application's performance by storing fragments of server-side rendered pages in edge cache servers. It means that after the first rendering, fragments of your pages will be served in a few milliseconds by servers close to your end users! It's a very efficient way to improve the performance and the SEO of your websites; and to dramatically reduce both your hosting costs and the energy consumption of these applications. Help the planet, use React ESI!

Because it is built on top of the Edge Side Includes (ESI) W3C specification, React ESI natively supports most of the well-known cloud cache providers including Cloudflare Workers, Akamai and Fastly. Of course, React ESI also supports the open source Varnish cache server that you can use in your own infrastructure for free (configuration example).

Also, React ESI allows to specify a different Time To Live (TTL) per React component and to generate the corresponding HTML asynchronously using a secure (signed) URL. The cache server fetches and stores in the cache all the needed fragments (the HTML corresponding to every React component), builds the final page and sends it to the browser. React ESI also allows components to (re-)render client-side without any specific configuration.

ESI example

Schema from The Varnish Book

Discover React ESI in depth with this presentation

Examples

Install

Using Yarn:

$ yarn add react-esi

Or using NPM:

$ npm install react-esi

Usage

React ESI provides a convenient Higher Order Component that will:

  • replace the wrapped component by an ESI tag server-side (don't worry React ESI also provides the tooling to generate the corresponding fragment);
  • render the wrapped component client-side, and feed it with the server-side computed props (if any).

React ESI automatically calls a static async method named getInitialProps() to populate the initial props of the component. Server-side, this method can access to the HTTP request and response, for instance, to set the Cache-Control header, or some cache tags.

These props returned by getInitialProps() will also be injected in the server-side generated HTML (in a <script> tag). Client-side the component will reuse the props coming from the server (the method will not be called a second time). If the method hasn't been called server-side, then it will be called client-side the first time the component is mounted.

The Higher Order Component

// pages/index.js
import React from 'react';
import withESI from 'react-esi';
import MyFragment from 'components/MyFragment';

const MyFragmentESI = withESI(MyFragment, 'MyFragment');
// The second parameter is an unique ID identifying this fragment.
// If you use different instances of the same component, use a different ID per instance.

const Index = () => (
  <div>
    <h1>React ESI demo app</h1>
    <MyFragmentESI greeting="Hello!" />
  </div>
);
// components/MyFragment.js
import React from 'react';

export default class MyFragment extends React.Component {
  render() {
    return (
      <section>
        <h1>A fragment that can have its own TTL</h1>

        <div>{this.props.greeting /* access to the props as usual */}</div>
        <div>{this.props.dataFromAnAPI}</div>
      </section>
    );
  }

  static async getInitialProps({ props, req, res }) {
    return new Promise(resolve => {
      if (res) {
        // Set a TTL for this fragment
        res.set('Cache-Control', 's-maxage=60, max-age=30');
      }

      // Simulate a delay (call to a remote service such as a web API)
      setTimeout(
        () =>
          resolve({
            ...props, // Props coming from index.js, passed through the internal URL
            dataFromAnAPI: 'Hello there'
          }),
        2000
      );
    });
  }
}

The initial props must be serializable using JSON.stringify(). Beware Map, Set and Symbol!

Note: for convenience, getInitialProps() has the same signature than the Next.js one. However, it's a totally independent and standalone implementation (you don't need Next.js to use it).

Serving the Fragments

To serve the fragments, React ESI provides a ready to use controller compatible with Express:

// server.js
import express from 'express';
import { path, serveFragment } from 'react-esi/lib/server';

const server = express();
server.use((req, res, next) => {
  // Send the Surrogate-Control header to announce ESI support to proxies (optional with Varnish, depending of your config)
  res.set('Surrogate-Control', 'content="ESI/1.0"');
  next();
});

server.get(path, (req, res) =>
  // "path" default to /_fragment, change it using the REACT_ESI_PATH env var
  serveFragment(
    req,
    res,
    // "fragmentID" is the second parameter passed to the "WithESI" HOC, the root component used for this fragment must be returned
    fragmentID => require(`./components/${fragmentID}`).default) 
);

// ...
// Other Express routes come here

server.listen(80);

Alternatively, here is a full example using a Next.js server:

// server.js
import express from 'express';
import next from 'next';
import { path, serveFragment } from 'react-esi/lib/server';

const port = parseInt(process.env.PORT, 10) || 3000
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()

app.prepare().then(() => {
  const server = express();
  server.use((req, res, next) => {
    // Send the Surrogate-Control header to announce ESI support to proxies (optional with Varnish)
    res.set('Surrogate-Control', 'content="ESI/1.0"');
    next();
  });

  server.get(path, (req, res) =>
    serveFragment(req, res, fragmentID => require(`./components/${fragmentID}`).default)
  );
  server.get('*', handle); // Next.js routes

  server.listen(port, err => {
    if (err) throw err;
    console.log(`> Ready on http://localhost:${port}`);
  });
});

Features

  • Support Varnish, Cloudflare Workers, Akamai, Fastly and any other cache systems having ESI support
  • Written in TypeScript
  • Next.js-friendly API

Environment Variables

React ESI can be configured using environment variables:

  • REACT_ESI_SECRET: a secret key used to sign the fragment URL (default to a random string, it's highly recommended to set it to prevent problems when the server restart, or when using multiple servers)
  • REACT_ESI_PATH: the internal path used to generate the fragment, should not be exposed publicly (default: /_fragment)

Passing Attributes to the <esi:include> Element

To pass attributes to the <esi:include> element generated by React ESI, pass a prop having the following structure to the HOC:

{
  esi: {
    attrs: {
      alt: "Alternative text",
      onerror: "continue"
    }
  }
}

Troubleshooting

The Cache is Never Hit

By default, most cache proxies, including Varnish, never serve a response from the cache if the request contains a cookie. If you test using localhost or a similar local domain, clear all pre-existing cookies for this origin. If the cookies are expected (e.g.: Google Analytics or ad cookies), then you must configure properly your cache proxy to ignore them. Here are some examples for Varnish.

Design Considerations

To allow the client-side app to reuse the props fetched or computed server-side, React ESI injects <script> tags containing them in the ESI fragments. After the assembling of the page by the cache server, these script tags end up mixed with the legit HTML. These tags are automatically removed from the DOM before the rendering phase.

Going Further

React ESI plays very well with advanced cache strategies including:

  • Cache invalidation (purge) with cache tags (Varnish / Cloudflare)
  • Warming the cache when data change in the persistence layer (Varnish)

Give them a try!

Vue.js / Nuxt

We love Vue and Nuxt as much as React and Next, so we're a currently porting React ESI for this platform. Contact us if you want to help!

Credits

Created by Kévin Dunglas. Sponsored by Les-Tilleuls.coop.

Comments
  • fix: content truncated because response end is called too early

    fix: content truncated because response end is called too early

    In some case the res.end is called too early. We should let the pipe end the writer when the reader ends.

    Tested with large ESI. The transformation is working but the last part is not sent.

    opened by jamyouss 7
  • Very large ESI are truncated

    Very large ESI are truncated

    Hello,

    First thanks for you work and in particular this implementation of ESI with React (and Next.js in my case).

    I am currently facing an issue with contents that have very large size (about 2mb), generated HTML from ESI is missing some ending tags. I have a Content component that is used to create the HOC (ContentESI). This component calls an API to get its data in getInitialProps. The return of API is complete, the props in window.__REACT_ESI__ are complete. Content component is using many others components to render parts of the API response. When I render Content without ESI, generated HTML is complete. But when I use the HOC, generated HTML is missing data at the end (so in my case, closing tags).

    My knowledge in Node.js & React are very limited, I don't know where to start. I think that it is an issue with Stream, Transform or renderToNodeStream (based on my reading of server.tsx).

    I have done tests with:

    • Node.JS 12.x, React 16.x, Next.js 9.5, React ESI 0.3
    • Node.JS 12.x, React 17.x, Next.js 9.5, React ESI 0.3
    • Node.JS 14.x, React 16.x, Next.js 9.5, React ESI 0.3
    • Node.JS 12.x, React 17.x, Next.js 9.5, React ESI 0.3
    • Node.JS 12.x, React 16.x, Next.js 9.5, React ESI 0.2
    opened by julienlary-dkt 6
  • Mark react 17 as being supported

    Mark react 17 as being supported

    @dunglas It's been tested on some projects of mine, and I can confirm it works with 17 at least. It might work on 18 too but I did not test it yet.

    If you'd rather have another nomenclature to specify the 17 version (such as ^17.0.0) please let me know.

    Thanks!

    opened by Paulmolin 2
  • Error with multiple esi-includes on one page

    Error with multiple esi-includes on one page

    Hello @dunglas

    Thanx for your great work!

    I have a php website where I want to include multiple esi-includes : <esi:include src="/esi/fragment?param=1" alt="Alternative text1" /> <esi:include src="/esi/fragment?param=2" alt="Alternative text2" />

    On the other hand I have nextjs in place with version 9.1.5 with customized server.js: server.js `const express = require('express') const next = require('next') const { path, serveFragment } = require('react-esi/lib/server')

    const dev = process.env.NODE_ENV !== 'production' const app = next({ dev }) const handle = app.getRequestHandler()

    app.prepare().then(() => { const server = express()

    server.use((req, res, next) => { // Send the Surrogate-Control header to announce ESI support to proxies (optional with Varnish) res.set('Surrogate-Control', 'content="ESI/1.0"') next() })

    server.get(path, (req, res) => serveFragment( req, res, fragmentID => require(./components/${fragmentID}).default ) ) server.get('*', handle)

    server.listen(3000, err => { if (err) throw err console.log(> Ready on http://localhost:3000) }) })`

    package.json { "name": "nextson", "version": "1.0.0", "private": true, "main": "dist/server.js", "scripts": { "dev": "node server.js", "build_old": "next build", "start_old": "next start", "build": "next build", "start": "NODE_ENV=production node server.js" }, "dependencies": { "@zeit/next-css": "^1.0.1", "@zeit/next-sass": "^1.0.1", "dotenv-webpack": "1.5.7", "express": "^4.17.1", "isomorphic-unfetch": "^3.0.0", "next": "^9.1.5", "nextjs-redirect": "^1.0.2", "node-sass": "^4.13.0", "react": "^16.9.0", "react-dom": "^16.9.0", "react-esi": "^0.2.0", "react-slick": "^0.25.2", "slick-carousel": "^1.8.1", "url-loader": "^2.2.0" }, "devDependencies": { "@babel/cli": "^7.6.0", "@babel/node": "^7.6.1" } }

    pages/hoc/fragment.js `import React from 'react'; import withESI from 'react-esi'; import Layout from '../../components/layout'; import myfragment from '../../components/myfragment';

    //const MyFragmentESI = withESI(myfragment, 'myfragment'); // The second parameter is an unique ID identifying this fragment. // If you use different instances of the same component, use a different ID per instance.

    class Fragment extends React.Component { static getInitialProps({query}) { return {query} }

    render() {
        console.log(this.props.query.param);
        const name = 'myfragment_'+this.props.query.param;
        console.log(name);
        const MyFragmentESI = withESI(myfragment, name);
        return(
          <Layout>
            <h1>React ESI demo app</h1>
            <MyFragmentESI greeting="test greeting!" />
          </Layout>
        );
    }
    

    }

    export default Fragment; `

    components/layout.js import Link from 'next/link'

    export default ({ children, title = 'This is the default title' }) => (

    {children}
    
    <footer>{'I`m here to stay'}</footer>
    
    )

    components/myfragment.js `import React from 'react';

    export default class myfragment extends React.Component {

    constructor(props) { super(props) this.click = this.click.bind(this) }

    click() {

    }

    render() { return (

    A fragment that can have its own TTL

    {this.props.greeting}
    {this.props.dataFromAnAPI}
    <button onClick={this.click}>Take the Shot!
    ); }

    static async getInitialProps({ props, req, res }) { if (res) { res.setHeader('Surrogate-Control','content="ESI/1.0"'); }

    return new Promise(resolve => {
      if (res) {
        // Set a TTL for this fragment
        res.setHeader('Cache-Control', 's-maxage=60, max-age=30');
      }
    
      // Simulate a delay (call to a remote service such as a web API)
      setTimeout(
        () =>
          resolve({
            ...props, // Props coming from index.js, passed through the internal URL
            dataFromAnAPI: 'Hello there'
          }),
        2000
      );
    });
    

    } } `

    varnish settings: /etc/varnish/default.vlc `

    backend nextjs1 { .host = "127.0.0.1"; .port = "3001"; .max_connections = 100; .first_byte_timeout = 800s; }

    sub vcl_recv { ... if ( req.url ~ "^/_next/") { set req.url = regsub(req.url, "^/nextjs/", "/"); set req.backend_hint = nextjs.backend(); return (hash); }

    if (req.url ~ "^/esi/") {
        set req.url = regsub(req.url, "^/esi/", "/hoc/");
        # Send Surrogate-Capability headers to announce ESI support to backend
        set req.http.Surrogate-Capability = "key=ESI/1.0";
        set req.backend_hint = nextjs.backend();
        return (hash);
    } 
    

    ... } sub vcl_backend_response {

    set beresp.do_esi = true;
    

    ... }

    ` Result: Screenshot 2019-12-16 at 23 00 16

    To u see by change what I am doing wrong? The ssr part is not working properly!

    getting following error: Screenshot 2019-12-16 at 23 01 37

    Thanx for your help! Would love to get your library into production

    Cheers Klausi

    opened by watzak 2
  • Feature - add option to further pipe stream

    Feature - add option to further pipe stream

    Hi,

    This PR aims to expose the serveFragment stream to the library user. That is, an option to provide any extra pipes on the stream is provided. With this option, users can further transform the fragment output as desired. I created this PR because I needed to add rendered styles from emotion to the served fragment.

    Changes:

    • options I've added an options argument to serveFragments. I was assuming that more options could follow
    • options.pipeStream After removing the react root transform stream, it will check if option.pipeStream is provided and executes it.

    I'd be happy to implement any desired changes.

    opened by dpnolte 1
  • Feature - add typescript declarations

    Feature - add typescript declarations

    Hi,

    Thanks for this awesome library.

    With this PR, I'd like to add typings to the package.

    There were a couple of issues with typing withESI:

    • Return type - With declarations enabled, typescript generated an error: the esi property cannot be private/protected in the HOC class. That is, exported anonymous classes can't have private or protected members if declaration emit is enabled, because there's no way to represent that in a .d.ts file. I resolved it by providing an return type to withESI React.ComponentClass<P & IWithESIProps>
    • propTypes - The problem with this return type is that the static propTypes member did not account for child properties as provided by the generic variable P. This generated another typescript error. I resolved it by converting the propTypes member first to unknown and then to the proper WeakValidationMap type to account for HOC props and the children props.
    opened by dpnolte 1
  • Expose original component as public static member WrappedComponent

    Expose original component as public static member WrappedComponent

    Hi, this PR will add a public static property WrappedComponent (tests included) to access original component.

    It looks like a de facto standard in higher order components, at least that's what react-router and react-redux do, so I expected any higher order component to do the same. This allows to access original component in a standardized way and access its original static properties (in my case, a loadData property used for server-side data fetching, but that could be anything else).

    Thanks for your work!

    opened by naholyr 1
  • Bump json5 from 2.1.3 to 2.2.3

    Bump json5 from 2.1.3 to 2.2.3

    Bumps json5 from 2.1.3 to 2.2.3.

    Release notes

    Sourced from json5's releases.

    v2.2.3

    v2.2.2

    • Fix: Properties with the name __proto__ are added to objects and arrays. (#199) This also fixes a prototype pollution vulnerability reported by Jonathan Gregson! (#295).

    v2.2.1

    • Fix: Removed dependence on minimist to patch CVE-2021-44906. (#266)

    v2.2.0

    • New: Accurate and documented TypeScript declarations are now included. There is no need to install @types/json5. (#236, #244)
    Changelog

    Sourced from json5's changelog.

    v2.2.3 [code, diff]

    v2.2.2 [code, diff]

    • Fix: Properties with the name __proto__ are added to objects and arrays. (#199) This also fixes a prototype pollution vulnerability reported by Jonathan Gregson! (#295).

    v2.2.1 [code, diff]

    • Fix: Removed dependence on minimist to patch CVE-2021-44906. (#266)

    v2.2.0 [code, diff]

    • New: Accurate and documented TypeScript declarations are now included. There is no need to install @types/json5. (#236, #244)
    Commits
    • c3a7524 2.2.3
    • 94fd06d docs: update CHANGELOG for v2.2.3
    • 3b8cebf docs(security): use GitHub security advisories
    • f0fd9e1 docs: publish a security policy
    • 6a91a05 docs(template): bug -> bug report
    • 14f8cb1 2.2.2
    • 10cc7ca docs: update CHANGELOG for v2.2.2
    • 7774c10 fix: add proto to objects and arrays
    • edde30a Readme: slight tweak to intro
    • 97286f8 Improve example in readme
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • Bump express from 4.17.1 to 4.17.3

    Bump express from 4.17.1 to 4.17.3

    Bumps express from 4.17.1 to 4.17.3.

    Release notes

    Sourced from express's releases.

    4.17.3

    4.17.2

    Changelog

    Sourced from express's changelog.

    4.17.3 / 2022-02-16

    4.17.2 / 2021-12-16

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • Bump qs from 6.5.2 to 6.5.3

    Bump qs from 6.5.2 to 6.5.3

    Bumps qs from 6.5.2 to 6.5.3.

    Changelog

    Sourced from qs's changelog.

    6.5.3

    • [Fix] parse: ignore __proto__ keys (#428)
    • [Fix] utils.merge`: avoid a crash with a null target and a truthy non-array source
    • [Fix] correctly parse nested arrays
    • [Fix] stringify: fix a crash with strictNullHandling and a custom filter/serializeDate (#279)
    • [Fix] utils: merge: fix crash when source is a truthy primitive & no options are provided
    • [Fix] when parseArrays is false, properly handle keys ending in []
    • [Fix] fix for an impossible situation: when the formatter is called with a non-string value
    • [Fix] utils.merge: avoid a crash with a null target and an array source
    • [Refactor] utils: reduce observable [[Get]]s
    • [Refactor] use cached Array.isArray
    • [Refactor] stringify: Avoid arr = arr.concat(...), push to the existing instance (#269)
    • [Refactor] parse: only need to reassign the var once
    • [Robustness] stringify: avoid relying on a global undefined (#427)
    • [readme] remove travis badge; add github actions/codecov badges; update URLs
    • [Docs] Clean up license text so it’s properly detected as BSD-3-Clause
    • [Docs] Clarify the need for "arrayLimit" option
    • [meta] fix README.md (#399)
    • [meta] add FUNDING.yml
    • [actions] backport actions from main
    • [Tests] always use String(x) over x.toString()
    • [Tests] remove nonexistent tape option
    • [Dev Deps] backport from main
    Commits
    • 298bfa5 v6.5.3
    • ed0f5dc [Fix] parse: ignore __proto__ keys (#428)
    • 691e739 [Robustness] stringify: avoid relying on a global undefined (#427)
    • 1072d57 [readme] remove travis badge; add github actions/codecov badges; update URLs
    • 12ac1c4 [meta] fix README.md (#399)
    • 0338716 [actions] backport actions from main
    • 5639c20 Clean up license text so it’s properly detected as BSD-3-Clause
    • 51b8a0b add FUNDING.yml
    • 45f6759 [Fix] fix for an impossible situation: when the formatter is called with a no...
    • f814a7f [Dev Deps] backport from main
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • Bump minimatch from 3.0.4 to 3.1.2

    Bump minimatch from 3.0.4 to 3.1.2

    Bumps minimatch from 3.0.4 to 3.1.2.

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • prop-types should be a dependency

    prop-types should be a dependency

    Regarding the official usage of prop-types: https://github.com/facebook/prop-types#how-to-depend-on-this-package, its needs to be a dependencies instead of devDependencies.

    I would propose a PR if you like.

    opened by bobaaaaa 1
  • next.js example was removed from upstream next.js project

    next.js example was removed from upstream next.js project

    The example, which is currently linked in the react-esi readme, no longer exists: https://github.com/zeit/next.js/blob/canary/examples/with-react-esi/

    Is there a reason this was removed? i.e., something about it doesn't work correctly? Or has something changed in next.js that makes react-esi incompatible with it?

    opened by milesrichardson 1
  • Is there any downsides of opting-out from default Next.js server?

    Is there any downsides of opting-out from default Next.js server?

    Is there any downsides of opting-out from default Next.js server?

    On Next.js website it's stated:

    Before deciding to use a custom server please keep in mind that it should only be used when the >integrated router of Next.js can't meet your app requirements. A custom server will remove >important performance optimizations, like serverless functions and Automatic Static Optimization.

    opened by oogxdd 0
  • Handling complex project structure

    Handling complex project structure

    Two pieces of the README first:

    withESI usage:

    const MyFragmentESI = withESI(MyFragment, 'MyFragment');
    // The second parameter is an unique ID identifying this fragment.
    // If you use different instances of the same component, use a different ID per instance.
    

    serving the fragments:

    // "fragmentID" is the second parameter passed to the "WithESI" HOC, the root component used for this fragment must be returned
    fragmentID => require(`./components/${fragmentID}`).default) 
    

    First though is that the fragmentID is more than just an ID, from this example it seems like it needs to match the filename for the dynamic require to work properly. If I end up using different ID per instance as suggested I don't know how I'm gonna map the fragmentID to the relevant import path.

    I'm working with a very complex project structure with custom resolvers using environment variables so I don't have a flat /components/* folder.

    Is there a way to build a map fragmentID => requirePath before starting the server ?

    I've seen such algorithm with gettext-extractor where we look for every call of the "getText" function in the source files. Something like this:

    JsExtractors.callExpression(['getText'], {
        arguments: {
          text: 0,
          context: 1,
        },
      })
    

    We could look for every usage of withESI maybe ?

    Maybe I'm missing something obvious to solve this, let me know

    opened by VincentCharpentier 1
Owner
Kévin Dunglas
Founder of @coopTilleuls / Creator of @api-platform, Mercure.rocks and Vulcain.rocks / @symfony Core Team
Kévin Dunglas
A tiny, blazing fast view library that creates reactive Web Components

dlite A tiny, blazing fast view library that creates reactive Web Components ?? Complete documentation https://dlitejs.com ?? Introduction dlite creat

Adam Hill 20 Feb 25, 2023
Lightweight react-like library. Support for asynchronous rendering and hooks.

Recept · Lightweight react-like library. Like the name, this project is mainly based on the architectural idea of react, which can feel react more int

RuiLin Dong 52 Sep 17, 2022
⚡️ Lightning-fast search for React and React Native applications, by Algolia.

React InstantSearch is a library for building blazing fast search-as-you-type search UIs with Algolia. React InstantSearch is a React library that let

Algolia 2k Dec 27, 2022
The simple but very powerful and incredibly fast state management for React that is based on hooks

Hookstate The simple but very powerful and incredibly fast state management for React that is based on hooks. Why? • Docs / Samples • Demo application

Andrey 1.5k Jan 7, 2023
🔍 Holmes is a 0 config, fast and elementary state orchestrator for React

React Holmes ?? - Elementary State Orchestrator for React ?? Holmes is a 0 config, fast and elementary state orchestrator for React. Holmes has a very

null 49 Oct 15, 2022
The next open source file uploader for web browsers :dog:

Uppy Tests Deploys Uppy is a sleek, modular JavaScript file uploader that integrates seamlessly with any application. It’s fast, easy to use and lets

Transloadit 26.2k Jan 6, 2023
Next Generation Visual Programming Platform

unit is a General Purpose Visual Programming Language and Environment built with a primary focus on Developer Experience.

Samuel Timbó 1.1k Dec 28, 2022
A minimum and lightweight external store for React and React Native application

Reactive store - a minimum and lightweight external store for React and React Native application Table of contents Features Installation Usage 3.1 Cre

Hòa Võ 7 Nov 21, 2022
Maple.js is a React webcomponents based framework mixing ES6 with Custom Elements, HTML Imports and Shadow DOM. It has in-built support for SASS and JSX, including a Gulp task for vulcanizing your project.

Heroku: http://maple-app.herokuapp.com/ npm: npm install maple.js Bower: bower install maple.js Maple is a seamless module that allows you to organise

Adam Timberlake 430 Dec 23, 2022
React, React Native and Vue UI components for building data-driven apps with Elasticsearch

Reactive Search UI components library for Elasticsearch: Available for React, Vue and React Native Read how to build an e-commerce search UI a.) with

appbase.io 4.7k Jan 4, 2023
CSS media queries in react - for responsive design, and more.

react-responsive Information Package react-responsive Description Media queries in react for responsive design Browser Version >= IE6* Demo The best s

contra 6.5k Dec 30, 2022
A performant, scalable and pluggable approach to instrumenting your React application.

react-i13n react-i13n provides a performant, scalable and pluggable approach to instrumenting your React application. Typically, you have to manually

Yahoo 369 Dec 25, 2022
Configure and build views using JSON schemas mapped to React components

react-json-schema npm install react-json-schema Construct React elements from JSON by mapping JSON definitions to React components. Use react-json-sch

Club OS 161 Dec 22, 2022
React UI Components for macOS High Sierra and Windows 10

React UI Components for macOS High Sierra and Windows 10. npm install react-desktop --save Help wanted! I am looking for developers to help me develop

Gabriel Bull 9.4k Dec 24, 2022
:postbox: A simple and customizable React notifications system

Reapop A simple and customizable React notifications system Summary Compatibility Demo Installation Integration & usage With React & Redux With React

Louis Barranqueiro 1.4k Jan 5, 2023
Useful components and utilities for working with React

react-extras Useful components and utilities for working with React Install $ npm install react-extras Usage import React from 'react'; import {If} f

Sindre Sorhus 695 Jan 7, 2023
A way to seamlessly integrate React and AngularJS

angulareact A way to seamlessly integrate React and AngularJS. Great for projects slowly migrating from AngularJS to React, supports using React compo

tonkean 18 Oct 3, 2022
A tiny state manager for React, Svelte, Vue and vanilla JS

dotto.x Dotto.x is a tiny state manager for React, Svelte, and vanilla JS. Lightweight. Core is less than 135 bytes (minified and gzipped). Zero depen

null 108 Nov 2, 2022
Teaful - Tiny, easy and powerful React state management

Tiny, easy and powerful React state management library What advantages does it have? ✨ ?? ・Tiny: Less than 1kb package to manage your state in

Teaful 668 Dec 18, 2022