Lazy load components requiring authentication with react-redux - reactjs

I'm trying to create a website using react+redux.
I've already setup jwt authentication on the server.
What I'd like to do is to lazy load some of my components/containers and reducers so that they can be downloaded only by authenticated users. I already know how to hide components from unauthenticated users (client side), but I would prefer to prevent them from downloading the relative javascript code.
I am using webpack, and I've already looked into react-router and require-ensure (https://stackoverflow.com/a/33044701/2920112), but this approach doesn't seem to handle authentication at all.
I've also considered using fetch in some way (probably bundling the private code separately with webpack), but I wouldn't know what to do with the bundle once I fetch it.
Am I approaching the problem in the wrong way?
The only alternative I see is to provide two HTML files, one loading a webpack bundle with only the public content, and one downloading also the private code. This however seems really suboptimal.
What is the correct approach?

We solved this by using react-router:
<Route
key="secured_component"
path="/secured"
onEnter={handleEnterSecuredComponent}
getComponent=({nextState, cb) => {
require.ensure([], () => {
cb(null, require('YourComponent').default);
});
}}
/>
...
const handleEnterSecuredComponent = (nextState, replace) => {
const {login: {success}} = store.getState();
if (!success) {
replace('/login');
}
};
So your login page should set in redux {login: {success: true}} if user is authenticated.
If an authenticated user tries to access /secured, he will be redirected to /login.
the require.ensure does not play any role of authentication. It just an entry point for webpack to split the chunk of js files for lazy loading.

For anyone still looking into this, React has now added the ability to split the codeand do lazy-loading when using webpack:
https://reactjs.org/docs/code-splitting.html
While this by itself is not enough to require authentication for the lazy-loaded modules, it can be paired with some authorization mechanism living on a reverse-proxy.

Related

How to use Express routes with React.js frontend?

Can I use Express routing for sending the content of the pages? In classic HTML, you can do:
app.get("/admin", (req, res) => {
res.sendFile("admin.html"); // or res.render() for templating engines like EJS
});
Unfortunately, I am not able to use Express routing for serving the React pages. The only way I found was to use React Router, which technically gets the job done, but then I can't do anything else on the server-side, like validating the login. I could technically make an API endpoint on the server-side for that and then request it within the React JSX page itself, however, that'd be inconvenient for many reasons:
Having the requests be sent only after the page, which means tons of loading indicating and possible issues like the user being able to see the content he should not be able to see at all.
Most of the "on-page-visit" API requests would need to be protected with keys, like the Authorization key
If the API request is done anywhere on the client-side, the keys are insecure and also the response can be manually altered by the user which creates huge security violations.
If there was a React renderer for Express, in which you could render a React JSX file directly from the page (e.g. res.render("page.jsx")) which would compile React and send the pure HTML, that'd be great! But of course, I haven't been able to find such and I doubt there are any.
Yes you can, but only only with the bundled appilcation. You simply send the index.html you find in the build folder of your react application.
Would look like this:
Assuming that is you express index.js & that the react application lives in a "client" directory of your applicaiton.
const path = require("path");
app.get("*", (req, res) => {
res.sendFile(path.resolve(__dirname, "client", "build", "index.html"));
});

How can I create an app shell using Gatsby?

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.

React SSR(Server Side Rendering) for SEO before login and after login Create React App (CRA). How to do this in one project folder?

I have a question, suppose there are two scenarios before login and after login:
Before login
Website will be SEO with next js or some other way. And has few pages like blog, blog details, about, contact, and products etc.
After login
Normal feature like post, post details with CRA(Create React App) setup.
My question is how do we setup the project with before login in SSR and after login. I don’t want SSR after login because there are lots of load on server for each features and functionality.
Is there any solution?
I have few article on isomorphic like https://hackernoon.com/get-an-isomorphic-web-app-up-and-running-in-5-minutes-72da028c15dd
example starter kit project: https://github.com/xiaoyunyang/isomorphic-router-demo
Can we create both SSR and Create react app within one project setup?
If you're using an express server you can use ssr-for-bots middleware to apply ssr to certain routes only.
const ssrForBots = require("ssr-for-bots");
const defaultOptions = {
prerender: [], // Array containing the user-agents that will trigger the ssr service | uses Regex
exclude: ["/routesAfterLogin/"], // Array containing paths and/or extentions that will be excluded from being prerendered by the ssr service | uses Regex
useCache: true, // Variable that determins if we will use page caching or not
cacheRefreshRate: 86400, // Seconds of which the cache will be kept alive, pass 0 or negative value for infinite lifespan default 24 hours
};
app.use(ssrForBots(defaultOptions));
That way the paths before login will be SSR, and paths after login (let's say they all start with /app) will be excluded
Yes we can, there are some articles about that topic:
Upgrading a create-react-app project to a SSR + code splitting setup
Server-side rendering with create-react-app, code-splitting, preloaded data, React Router, Helmet, Redux, and Thunk

Handle redirects with OAuth 2.0?

What is a good way to handle redirects in React Native with OAuth? There are external APIs I need to call, so I’ve registered my app, but I’m unclear what the redirect URI should be. For a web app, it would make sense how to handle this, but I’m not sure with React Native.
What you need to do in React Native is setup your application for deep linking. A deep link is a way for another application or in this case your browser/WebView to say "Hey! I'd like to pass this information back to a native app".
Setup:
Setup a url scheme in Xcode. This will allow you to redirect to url's formatted something like this myApp://oauthLogin
Setup Linking
From there you should be able to create an event listener for the Redirect URI that you pass to the oauth service, in this case your deep link.
componentDidMount() {
Linking.addEventListener('url', (url) => {
console.log(url);
// => myApp://oauthLogin?authCode=abc123
});
}
You will have to add extra code the make sure the url is in the correct format but i hope that gets you closer!

Is it possible to code split (webpack) with static single page app? (React/React-router)

I am aware of server side isomorphic rendering, but I currently have a site hosted on github pages so server-side isn't possible (or is it?).
I've been doing some research and found various comments saying that it is possible, but I'm looking for confirmation, and perhaps a more detailed explanation of how code-splitting is possible with a static single page app. My bundle.js file is currently 500+kb, and I'd like to see how I can reduce load-time, especially as I continue adding features.
If I recall with react-router you can define a parameter in your Route component getComponent(), and use System.import to load your dependencies e.g.
{
path: '/',
getComponent(location, cb) {
System.import('path/Component').then(loadRoute(cb)).catch(errorLoading);
}

Resources