How can I create an app shell using Gatsby? - reactjs

I've been in the process of improving considerably the performance of my react application (Created with create-react-app). I'm hosting my application in AWS S3 and I'd like to avoid server-side rendering so I can leverage the hassle-free world of static hosting. To make the long story short, I'd like to extract the app's shell (Meaning The footer, header, and sidebar into a static content, the latter would be rehydrated and supercharged with more details once the user logs in), and the terms of service, registration, and about pages to static. Then the application would be entirely dynamic in its nature (including the main index entry).
I tried using react-snap but it's having trouble rendering the service worker, and it doesn't give me the full experience as this application is behind an authentication wall (I had to make some compromises like asking manually the user to login, which I'd like this process to be automatic).
I saw that Gatsby can fit the needs that I'm looking for (My App is already architected in Reach Router). I don't want (for now) any other features, just the pre-rendering of the app shell, about, terms of service, and registration pages.
How can I achieve this?
I have already booted up the app in Gatsby, and loaded the main page. But if I change a route, I get hit by a 404 (which is normal, as I have not defined them inside pages). I checked the documentation and some starters, but I can't seem to find my answer.
Here's my only file in /src/pages.
// src/pages/index.tsx
import React from 'react';
import Root from '../views/Root';
export default () => <Root />;
Where <Root /> is my entire app.
(I know the about page is not going to be static as it hasn't been defined inside /src/pages)
I tried adding this in gatsby-node.js so I could catch all the routes as dynamic, except the about page, but it hasn't worked.
// gatsby-node.js
// Includes everything but the about page.
const regex = /^((?!(\/about)).)*$/;
exports.onCreatePage = async ({ page, actions }) => {
const { createPage } = actions;
// Only update the `/app` page.
if (page.path.match(regex)) {
// page.matchPath is a special key that's used for matching pages
// with corresponding routes only on the client.
page.matchPath = '/*';
// Update the page.
createPage(page);
}
};
How can I achieve this?

You can use the gatsby plugin "gatsby-plugin-offline" which will not only setup your website to work offline and cache your requests, it also comes with built in app shell functionality.
https://www.gatsbyjs.com/plugins/gatsby-plugin-offline/?=offline
From the link above:
App shell and server logs Server logs (like from Netlify analytics) may show a large number of pageviews to a route like
/offline-plugin-app-shell-fallback/index.html, this is a result of
gatsby-plugin-offline adding an app shell to the page. The app shell
is a minimal amount of user interface that can be cached offline for
reliable performance loading on repeat visits. The shell can be loaded
from the cache, and the content of the site loaded into the shell by
the service worker.

Related

Code splitting in react with respect to serviceworker

I have a react application running on example.com/web, which has menus like register, login, and various other pages mainly static which describe what this app is all about. Now once someone logs in I have example.com/app which opens the application, the dashboard, forms, and again many other things related to the application.
I have set different layouts for example.com/web and exapmle.com/app. and when people visit example.com they are auto-redirected to example.com/web
I have implemented lazy loading for /web and /app.
The problem is when someone visits example.com the serviceworker downloads all the files, which may not be required for people visiting the page only to check about the application.
Now I am looking for something where serviceworker downloads only web components and if required then app components. Maybe something like to break this whole react application into two different applications. I can not remove the serviceworker. I'm also not getting any idea what best can be done to reduce the network call. Do let me know what best can be done. I check a few examples on the subdomain and I think it is again a single react app and serviceworker will download all the files.
And if I break it into two different apps how will I pass authenticated props from the login page which is in /web to /app.
Any help?

How to pass query string from Shopify to an embedded app?

I'm building a Shopify app with Next.js and I need to grab the query string so I can check in getServerSideProps the identity of the merchant (bear in mind that Cookies are not recommended for Shopify apps)
When visiting some apps I noticed some of them are getting the query string passed down from Shopify in each request.
This image shows how it should look on each request
This image shows how my app behaves
In this image you can see that when you hover the routes no query strings are present, meaning that are passed somehow by the parent app.
As of right now I'm using a Cookie to pass the shopOrigin but I feel like it's not necessary if somehow I'm able to get the query string in each request, also with the HMAC I will be able to verify that the requests are coming from Shopify.
Any calls to your App originating from Shopify properly provide the shop parameter when they make requests. In your own App calls to itself, you would also likely be using the shop name as a query string value.
Note that you are still able to validate your sessions internally using a cookie, you just don't do it via the third-party route, outside the iframe, like we used to. Shopify has plenty of documentation on how to properly authenticate, and construct Apps, check them out. They even give you a working Node App to play with, so you can ensure you get it right.
The solution was pretty straightforward.
Shopify provides a TitleBar AppBridge component that you can use to to handle the App's navigation. What it does is that on each route change it reloads the iframe and the hmac, shop, code and timestamp are coming in the request. It's a tad slower then client side routing but it works as expected.
In order to use it you just need to go to:
Partner's dashboard / Your App / Extensions / Embedded App (click Manage) / Navigation (click Configure) and add navigation links, then you just need to import TitleBar from app-bridge-react and put it in index.js

Routing an user in a single page application using the adress bar

I have a backend using express to serve a static directory, to the path /, in which is contained a single page frontend. This backend also serves an API REST.
The frontend is built in React, and uses react-router to route the user from the different views of the web application.
If my react-router have two entries, let say /app and /config,
how can I redirect the client to that view of the application, if the user enters directly the URL in the web browser's address bar?
Right now, if I do that, Express gets the request and obviously returns a 404 message, as the single page is served to / path.
A simple way to resolve that is to always (even on 404s) send to user the index.html in your express route handlers.
See: https://stackoverflow.com/a/25499007/2624575
However, you need to take care of some things:
1) Your React Router code should start to handle 404s: https://stackoverflow.com/a/37491381/2624575
2) You need to handle correctly the path to your assets (icons, css, js, etc), otherwise you'll send the same index.html to those kind of resources (which will make your page render incorrectly)
3) Make sure that react-router is using browserHistory (the history that doesn't use hashes #), This way React will be able to render your routes correctly
Hope it helps!

Serving a static html page from a single page react app with react router

I have a react single page app, and am looking at serving a static html, SEO friendly landing page in the scenario where the user is not logged in. I'd like for that one page to be browsable by all search engines (the rest of the site is password protected to SEO doesn't matter.
I'm using react router, and can't find a way in the app to redirect the user to the static html file (which would hence be served server side) if the app finds they're not logged in.
Any suggestions? Thanks!
This is something you could do in your router on the server. You can't do it in your React app, because that defeats the purpose of having JS-less content to serve (since you'd be using JS to deliver the "static" content).
If you don't have a server set up yet with a router, that will take some time. But once you do, a simple check in the route will suffice.
// in hapijs, for example:
handler(request, reply) {
if (isAuthenticated(request)) {
reply.view('dashboard')
} else {
reply.view('static_page')
}
}

caching app shell in a React PWA with Server-Side rendering

So lets say you have a React-based mobile web app, that takes advantage of server-side rendering for the initial view ( for speed + SEO reasons ). There is no "index.html" file - the index file is dynamically built server-side and returned in the initial response.
Now lets say you want to add PWA functionality to that app. You hook up a service worker to cache assets, etc.
One of the core tenants of PWA's is that they provide an offline experience. Say we just want to show a refresh page, "You're offline, click here to refresh", when the service worker detects the user is offline.
Online examples provided by google talk about using an App Shell -- a static HTML file, which can be cached by the service worker on initial visit, and which will be the "shell" your react app lives inside. This shell ties in to showing an "offline" view.
How does this work with server-side rendering, where there is no "shell" html file, and each route can potentially return a different index.html file?
Any demos or examples of this functionality in the wild?
Any demos or examples of this functionality in the wild?
Yes!
Take a look at https://github.com/GoogleChrome/sw-precache/tree/master/app-shell-demo, which uses the dynamicUrlToDepndencies option in sw-precache to define which underlying resources are used to server-render the App Shell HTML.
The service worker it generates will take care of updating the App Shell HTML whenever any of the resources it depends on changes.
In this model the service worker will return the same App Shell HTML document for all navigation requests, so it assumes that the App Shell HTML is generic enough to then be populated at runtime with the dynamic content that's associated with the actual URL via your standard client-side routing logic.

Resources