{"id":13400790,"url":"https://github.com/dunglas/react-esi","last_synced_at":"2025-05-16T03:05:49.272Z","repository":{"id":34083563,"uuid":"169718534","full_name":"dunglas/react-esi","owner":"dunglas","description":"React ESI: Blazing-fast Server-Side Rendering for React and Next.js","archived":false,"fork":false,"pushed_at":"2024-03-19T11:11:13.000Z","size":542,"stargazers_count":679,"open_issues_count":12,"forks_count":31,"subscribers_count":14,"default_branch":"main","last_synced_at":"2025-04-08T13:07:39.592Z","etag":null,"topics":["cache","cloudflare-worker","esi","hacktoberfest","nextjs","performance","react","ssr","varnish"],"latest_commit_sha":null,"homepage":"https://dunglas.fr/2019/04/react-esi-blazing-fast-ssr/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dunglas.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"dunglas"}},"created_at":"2019-02-08T10:31:00.000Z","updated_at":"2025-03-06T16:53:07.000Z","dependencies_parsed_at":"2024-03-19T12:32:08.603Z","dependency_job_id":"f6743663-ac02-4aae-a4c6-f213b67c136d","html_url":"https://github.com/dunglas/react-esi","commit_stats":{"total_commits":51,"total_committers":9,"mean_commits":5.666666666666667,"dds":0.607843137254902,"last_synced_commit":"049b94dd275997cb739931d2a8850d184034efb4"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dunglas%2Freact-esi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dunglas%2Freact-esi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dunglas%2Freact-esi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dunglas%2Freact-esi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dunglas","download_url":"https://codeload.github.com/dunglas/react-esi/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254459088,"owners_count":22074605,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cache","cloudflare-worker","esi","hacktoberfest","nextjs","performance","react","ssr","varnish"],"created_at":"2024-07-30T19:00:55.494Z","updated_at":"2025-05-16T03:05:44.264Z","avatar_url":"https://github.com/dunglas.png","language":"TypeScript","funding_links":["https://github.com/sponsors/dunglas"],"categories":["Performance","Uncategorized","TypeScript","React [🔝](#readme)"],"sub_categories":["Server-Side Rendering","Uncategorized"],"readme":"# React ESI: Blazing-fast Server-Side Rendering for React and Next.js\n\n![CI status](https://github.com/github/docs/actions/workflows/test.yml/badge.svg)\n[![Coverage Status](https://coveralls.io/repos/github/dunglas/react-esi/badge.svg?branch=master)](https://coveralls.io/github/dunglas/react-esi?branch=master)\n[![npm version](https://badge.fury.io/js/react-esi.svg)](https://badge.fury.io/js/react-esi)\n[![MIT Licence](https://badges.frapsoft.com/os/mit/mit.svg?v=103)](https://opensource.org/licenses/mit-license.php)\n\nReact ESI is a super powerful cache library for vanilla [React](https://reactjs.org/) and [Next.js](https://nextjs.org/) applications, that can make highly dynamic applications as fast as static sites.\n\nIt provides a straightforward way to boost your application's performance by storing **fragments** of server-side rendered pages in **edge cache servers**.  \nIt means that after the first rendering, fragments of your pages will be served in a few milliseconds by servers close to your end users!  \nIt'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!\n\nBecause it is built on top of the [Edge Side Includes (ESI)](https://www.w3.org/TR/esi-lang) W3C specification,\nReact ESI natively supports most of the well-known cloud cache providers including [Cloudflare Workers](https://blog.cloudflare.com/edge-side-includes-with-cloudflare-workers/), [Akamai](https://www.akamai.com/us/en/support/esi.jsp) and [Fastly](https://docs.fastly.com/guides/performance-tuning/using-edge-side-includes).\nOf course, React ESI also supports the open source [Varnish cache server](https://varnish-cache.org/intro/index.html#intro) that you can use in your own infrastructure for free ([configuration example](https://github.com/zeit/next.js/blob/canary/examples/with-react-esi/docker/varnish/default.vcl)).\n\nAlso, React ESI allows the specification of different Time To Live (TTL) per React component and generates the corresponding HTML asynchronously using a secure (signed) URL.\nThe 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.\nReact ESI also allows components to (re-)render client-side without any specific configuration.\n\n![ESI example](https://raw.githubusercontent.com/varnish/Varnish-Book/3bd8894181f5e42f628967d04f40116498d1f7f2/ui/img/esi.png)\n\n\u003e Schema from [The Varnish Book](https://info.varnish-software.com/resources/varnish-6-by-example-book)\n\n**[Discover React ESI in depth with this presentation](https://dunglas.fr/2019/04/react-esi-blazing-fast-ssr/)**\n\n## Examples\n\n- [Next.js, Express, and Varnish](https://github.com/dunglas/react-esi/tree/main/examples/next)\n- [React, Express, and Varnish](https://github.com/dunglas/react-esi/tree/main/examples/express)\n\n## Install\n\nUsing NPM:\n\n    $ npm install react-esi\n\nOr using Yarn:\n\n    $ yarn add react-esi\n\nOr using PNPM:\n\n    $ pnpm add react-esi\n\n## Usage\n\nReact ESI provides a convenient [Higher Order Component](https://reactjs.org/docs/higher-order-components.html) that will:\n\n- replace the wrapped component with an ESI tag server-side (don't worry React ESI also provides the tooling to generate the corresponding fragment);\n- render the wrapped component client-side, and feed it with the server-side computed props (if any).\n\nReact 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](https://api-platform.com/docs/core/performance/#enabling-the-built-in-http-cache-invalidation-system).\n\nThese props returned by `getInitialProps()` will also be injected in the server-side generated HTML (in a `\u003cscript\u003e` tag).\nClient-side the component will reuse the props coming from the server (the method will not be called a second time).\nIf the method hasn't been called server-side, then it will be called client-side the first time the component is mounted.\n\n### The Higher Order Component\n\n```javascript\n// pages/App.jsx\nimport withESI from \"react-esi/lib/withESI\";\nimport MyFragment from \"../components/MyFragment\";\n\nconst MyFragmentESI = withESI(MyFragment, \"MyFragment\");\n// The second parameter is an unique ID identifying this fragment.\n// If you use different instances of the same component, use a different ID per instance.\n\nexport const App = () =\u003e (\n  \u003cdiv\u003e\n    \u003ch1\u003eReact ESI demo app\u003c/h1\u003e\n    \u003cMyFragmentESI greeting=\"Hello!\" /\u003e\n  \u003c/div\u003e\n);\n```\n\n```javascript\n// components/MyFragment.jsx\nimport React from \"react\";\n\nexport default class MyFragment extends React.Component {\n  render() {\n    return (\n      \u003csection\u003e\n        \u003ch1\u003eA fragment that can have its own TTL\u003c/h1\u003e\n\n        \u003cdiv\u003e{this.props.greeting /* access to the props as usual */}\u003c/div\u003e\n        \u003cdiv\u003e{this.props.dataFromAnAPI}\u003c/div\u003e\n      \u003c/section\u003e\n    );\n  }\n\n  static async getInitialProps({ props, res }) {\n    return new Promise((resolve) =\u003e {\n      if (res) {\n        // Set a TTL for this fragment\n        res.set(\"Cache-Control\", \"s-maxage=60, max-age=30\");\n      }\n\n      // Simulate a delay (call to a remote service such as a web API)\n      setTimeout(\n        () =\u003e\n          resolve({\n            ...props, // Props coming from index.js, passed through the internal URL\n            dataFromAnAPI: \"Hello there\",\n          }),\n        2000\n      );\n    });\n  }\n}\n```\n\nThe initial props **must** be serializable using `JSON.stringify()`. Beware `Map`, `Set`, and `Symbol`!\n\nNote: for convenience, `getInitialProps()` has the same signature as the Next.js one.\nHowever, it's a totally independent and standalone implementation (you don't need Next.js to use it).\n\n### Serving the Fragments\n\nTo serve the fragments, React ESI provides a ready-to-use controller compatible with [Express](https://expressjs.com/), check out [the full example](https://github.com/dunglas/react-esi/tree/main/examples/express).\n\nAlternatively, here is a full example using [a Next.js server](https://github.com/dunglas/react-esi/tree/main/examples/next):\n\n## Features\n\n- Support Varnish, Cloudflare Workers, Akamai, Fastly, and any other cache systems having ESI support\n- Written in TypeScript\n- Next.js-friendly API\n\n## Environment Variables\n\nReact ESI can be configured using environment variables:\n\n- `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**)\n- `REACT_ESI_PATH`: the internal path used to generate the fragment, should not be exposed publicly (default: `/_fragment`)\n\n## Passing Attributes to the `\u003cesi:include\u003e` Element\n\nTo pass attributes to the `\u003cesi:include\u003e` element generated by React ESI, pass a prop having the following structure to the HOC:\n\n```javascript\n{\n  esi: {\n    attrs: {\n      alt: \"Alternative text\",\n      onerror: \"continue\"\n    }\n  }\n}\n```\n\n## Troubleshooting\n\n### The Cache is Never Hit\n\nBy default, most cache proxies, [including Varnish](https://book.varnish-software.com/4.0/chapters/Content_Composition.html#cookies), never serve a response from the cache if the request contains a cookie.\nIf you test using `localhost` or a similar local domain, **clear all pre-existing cookies for this origin**.\nIf 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](https://www.varnish-software.com/wiki/content/tutorials/varnish/sample_vclTemplate.html#cookie-manipulation).\n\n## Design Considerations\n\nTo allow the client-side app to reuse the props fetched or computed server-side, React ESI injects `\u003cscript\u003e` tags containing them in the ESI fragments.\nAfter the assembling of the page by the cache server, these script tags end up mixed with the legit HTML.\nThese tags are automatically removed from the DOM before the rendering phase.\n\n## Going Further\n\nReact ESI plays very well with advanced cache strategies including:\n\n- Cache invalidation (purge) with cache tags ([Varnish](https://github.com/varnish/varnish-modules/blob/master/docs/vmod_xkey.rst) / [Cloudflare](https://blog.cloudflare.com/introducing-a-powerful-way-to-purge-cache-on-cloudflare-purge-by-cache-tag/))\n- Warming the cache when data changes in the persistence layer ([Varnish](https://blog.theodo.fr/2015/11/auto-warm-up-varnish4-cache/))\n\nGive them a try!\n\n## Vue.js / Nuxt\n\nWe love Vue and Nuxt as much as React and Next, so we're currently porting React ESI for this platform.\nContact us if you want to help!\n\n## Credits\n\nCreated by [Kévin Dunglas](https://dunglas.dev).\nSponsored by [Les-Tilleuls.coop](https://les-tilleuls.coop).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdunglas%2Freact-esi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdunglas%2Freact-esi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdunglas%2Freact-esi/lists"}