This guide shows you how to serve a React application to Edgio. If you’re using Next.js specifically, we suggest using the Next.js guide.
Example
Here’s an example React app running on Edgio:
Prerequisites
Setup requires:
- An Edgio account. Sign up for free.
- An Edgio property. Learn how to create a property.
- Node.js. View supported versions and installation steps.
- Edgio CLI.
Install the Edgio CLI
If you have not already done so, install the Edgio CLI.
Bash
1npm i -g @layer0/cli@latest
New project
This guide will use Create React App to generate a project. You can also reference the example app for a complete version of the code.
Bash
1npx create-react-app layer0-cra2cd layer0-cra30 init4# Pick the following options for questions5# > Add Edgio to the current app6# Hostname of origin site > layer0-docs-layer0-examples-api-default.layer0-limelight.link
Follow the additional sections below regarding the Create React App setup to finish the project setup.
Existing project
Then, in the root folder of your project, run:
Bash
10 init
This will automatically add all of the required dependencies and files to your project. These include:
- The
@layer0/core
package - Allows you to declare routes and deploy your application to Edgio. - The
@layer0/prefetch
package - Allows you to configure a service worker to prefetch and cache pages to improve browsing speed. layer0.config.js
- The main configuration file for Edgio.routes.js
- A default routes file that sends all requests to React. This file can be updated add caching or proxy URLs to a different origin.
Configure your project
Edgio Router
Using the
Router
class from @layer0/core
, you’ll configure caching for each of your routes, and forward requests to the server module you configured in the previous section using the proxy
function.Note: Change
dist
to match whatever your configured output file is.General routes file for React app
JavaScript
1// routes.js23import { Router } from '@layer0/core/router'4import { BACKENDS } from '@layer0/core'56new Router()7 .get('/service-worker.js', ({ serviceWorker }) => {8 serviceWorker('dist/service-worker.js')9 })10 .get('/p/:id', ({ cache }) => {11 // cache product pages at the edge for 1 day12 cache({13 edge: {14 maxAgeSeconds: 60 * 60 * 24, // 1 day15 },16 })17 })18 .fallback(({ renderWithApp }) => {19 // send all requests to the server module configured in layer0.config.js20 renderWithApp()21 })
Create React App Example
After following the instructions from above, update your
routes.js
file to match this.JavaScript
1// routes.js23const { Router } = require('@layer0/core/router')45const ONE_HOUR = 60 * 606const ONE_DAY = 24 * ONE_HOUR7const ONE_YEAR = 365 * ONE_DAY89const edgeOnly = {10 browser: false,11 edge: { maxAgeSeconds: ONE_YEAR },12}1314const edgeAndBrowser = {15 browser: { maxAgeSeconds: ONE_YEAR },16 edge: { maxAgeSeconds: ONE_YEAR },17}1819export default new Router()20 .prerender([{ path: '/' }])21 .match('/api/:path*', ({ cache, proxy }) => {22 cache(edgeAndBrowser)23 proxy('origin')24 })25 .match('/images/:path*', ({ cache, proxy }) => {26 cache(edgeAndBrowser)27 proxy('origin')28 })29 .match('/service-worker.js', ({ serviceWorker }) => serviceWorker('build/service-worker.js'))30 // match routes for js/css resources and serve the static files31 .match('/static/:path*', ({ serveStatic, cache }) => {32 cache(edgeAndBrowser)33 serveStatic('build/static/:path*')34 })35 // match client-side routes that aren't a static asset36 // and serve the app shell. client-side router will37 // handle the route once it is rendered38 .match('/:path*/:file([^\\.]+|)', ({ appShell, cache }) => {39 cache(edgeOnly)40 appShell('build/index.html')41 })42 // match other assets such as favicon, manifest.json, etc43 .match('/:path*', ({ serveStatic, cache }) => {44 cache(edgeOnly)45 serveStatic('build/:path*')46 })47 // send any unmatched request to origin48 .fallback(({ serveStatic }) => serveStatic('build/index.html'))
Prefetching
Install the
@layer0/react
to enable this feature.Bash
1npm i -D @layer0/react
Add the
Prefetch
component from @layer0/react
to your links to cache pages before the user clicks on them. Here’s an example:JavaScript
1import { Link } from 'react-router'2import { Prefetch } from '@layer0/react'34export default function ProductListing() {5 return (6 <div>7 {/* ... */}8 {/* The URL you need to prefetch is the API call that the page component will make when it mounts. It will vary based on how you've implemented your site. */}9 <Prefetch url="/api/products/1.json">10 <Link to="/p/1">Product 1</Link>11 </Prefetch>12 {/* ... */}13 </div>14 )15}
By default,
Prefetch
waits until the link appears in the viewport before prefetching. You can prefetch immediately by setting the immediately
prop:JavaScript
1<Prefetch url="/api/products/1.json" immediately>2 <Link to="/p/1">Product 1</Link>3</Prefetch>
Service Worker
In order for prefetching to work, you need to configure a service worker that uses the
Prefetcher
class from @layer0/prefetch
.Following the Create React App example from above? Make sure to create a file in
src/service-worker.js
. Paste the code example below into that file.Here is an example service worker:
JavaScript
1import { skipWaiting, clientsClaim } from 'workbox-core'2import { precacheAndRoute } from 'workbox-precaching'3import DeepFetchPlugin from '@layer0/prefetch/sw/DeepFetchPlugin'4import { Prefetcher } from '@layer0/prefetch/sw'56skipWaiting()7clientsClaim()8precacheAndRoute(self.__WB_MANIFEST || [])910new Prefetcher({11 plugins: [12 // Enable this as part of the example in this guide13 // new DeepFetchPlugin([14 // {15 // jsonQuery: 'picture',16 // as: 'image',17 // },18 // ]),19 ],20}).route()
In order to install the service worker in the browser when your site loads, call the
install
function from @layer0/prefetch
.JavaScript
1import { install } from '@layer0/prefetch/window'23install()
If following the Create React App example, this can be done in the same location as App initialization in
index.js
after the ReactDOM.render
call.Server Side Rendering
React offers a great amount of flexibility in how you set up server side rendering. Frameworks like Next.js offer a standardized, built-in way of implementing SSR. If you’re using Next.js specifically, we suggest using the Next.js guide. We’ll assume at this point that you’re not using Next.js, but have an existing Node app that is doing server-side rendering.
In order to render on Edgio, you need to provide a function that takes a Node
Request
and Response
and sends the HTML that results from the renderToString()
method from react-dom/server
. Configure that function using the server
property of layer0.config.js
. Here’s an example:JavaScript
1// layer0.config.js23module.exports = {4 server: {5 path: '0/server.js',6 },7}
JavaScript
1// server.js - basic node example23const ReactDOMServer = require('react-dom/server')4const App = require('./app')56module.exports = function server(request, response) {7 const html = ReactDOMServer.renderToString(React.createElement(App, { url: request.url }))8 response.set('Content-Type', 'text/html')9 response.send(html)10}
Express Example
If you already have an express app set up to do server side rendering, the server module can also export that instead:
JavaScript
1// server.js - express example23const express = require('express')4const app = express()5const ReactDOMServer = require('react-dom/server')6const App = require('./app')78app.use((request, response, next) => {9 const html = ReactDOMServer.renderToString(React.createElement(App, { url: request.url }))10 response.set('Content-Type', 'text/html')11 response.send(html)12})1314module.exports = app
Bundling your server with Webpack
We recommend bundling your server with Webpack. Your webpack config should use the following settings:
JavaScript
1module.exports = {2 target: 'node',3 mode: 'production',4 output: {5 filename: '[name].js',6 path: path.resolve(__dirname, '..', 'dist'), // should match server.path in layer0.config.js7 libraryTarget: 'umd',8 libraryExport: 'default',9 },10 entry: {11 server: './layer0/server.js', // this should point to your server entry point, which should export a function of type (request: Request, response: Response) => void or an express app as the default export.12 },13}
Deploying
Deploy your app to the Sites by running the following command in your project’s root directory:
Bash
10 deploy
If you have a static app or are following the above example then you need to build the app first
Bash
1npm run build20 deploy
For more on deploying, see Deploying.