Serve static assets with an efficient cache policy in REACT APP - reactjs

Lighthouse suggests the following:
"Serve static assets with an efficient cache policy".
But how can i add a cache policy in React app? I've used create-react-app but no serviceworker was authomatically created.
How can i tackle this?

That should be done note in "react app", but in the setting of your webserver.
for example if you use nginx take a look on this weblink https://serversforhackers.com/c/nginx-caching
or if you are using express http://expressjs.com/en/resources/middleware/serve-static.html

Related

How to serve React bundle.js with Traefik Ingress Controller?

I have a Golang/React app deployed on Kubernetes. One of the prefix paths my app uses is /staging. However, every time I try to access my app at hostname.com/staging I get an error 404 in the dev console saying it could not load bundle.js. Is there a configuration I need to take care of in React or is it something in my Golang server? Do I need to use React Router?

How to deploy Next.js app without Node.js server?

I was hoping to deploy a Next.js app with Laravel API. I had developed React apps with CRA and in those I used the API server to serve the index.html of the CRA as the entry point of the app.
But in Next.js, after development I get to know that it needs a Node.js server to serve (which is my bad, didn't notice that). There is an option next export that builds a static representation of the Next.js app and it has an index.html. I am serving the index.html as the entry of the app by my Laravel API. It is serving the page, but just some of the static contents.
What I was hoping to know is it possible to host the aPI and the Next app from a single PHP shared hosting without any node server? If so, how? If not so, what could be the alternatives?
Actually the acepted answer is completly wrong, when you do yarn build and in your package.json is set like "build": "next build && next export", you will get an out folder which all the items in there are used to build without node.js server
Now since you are using laravel, and you use the out folder you will only load half of the page because the routes are not set properly. for that to work you need to edit your next.config.js edit it to
module.exports = {
distDir: '/resources/views',
assetPrefix: '/resources/views',
}
These will set the root directory to the root one in Laravel. now this will work for SPA (single page application) only for the dynamic routes you need to match with a view file for each one that you have in your out folder
For each route that you have you need to create a new "get" route in laravel
Route::get('/', function () {
return require resource_path('views/index.html');
});
Route::get('/contacts', function () {
return require resource_path('views/contacts.html');
});
Route::get('/post/{slug}', function () {
return require resource_path('views/post/[slug].html');
});
Notice that you can pass a wildcard for dynamic routes and they are all gonna work. once you do that and you deploy route out folder inside /resources/views in Laravel it's going to work
Apparently there is no alternative to nodejs server, which is not an option for me currently, so I unfortunately had to abandon next.js and create a CRA app and used as much from the next.js as I could.

React/webpack - How can I host react app on one server and images/fonts on another server?

For business reasons, I have to host my React app on one domain and serve the images/fonts from another domain (ie. S3). Not sure how I can configure the app to do this?
An example, I want to host my React app at:
http://kamilski.com/#/
And then serve my static assets (images and fonts) from:
http://camel.assets.s3.com/***
I don't know how to configure my create-react-app or Webpack to do this. I know that PUBLIC_URL is available but that still forces me to run the React app and assets on the same server.
This isn't too bad - I do a similar thing with a couple of my apps.
First, get the assets you want onto S3 using an S3 bucket.
There's a good youtube video for that here (this is about uploading from your react app, but the AWS setup is similar in some ways): https://www.youtube.com/watch?v=cDj4LPTLR3o
So once you have your aws bucket setup, you'll probably have one called "site_images" for example. At that point you can source those images from S3 like you would any other image:
https://camel.assets.s3.amazonaws.com/images/SOME-IMAGE-ON-AWS
You'd load fonts in a similar way via your css file(s) most likely with something like:
#fontface {
font-family: 'My Awesome Font';
src: url('https://camel.assets.s3.amazonaws.com/fonts/SOME-FONT-ON-AWS')
}
How you do this specifically will depend on your configuration. You'll need to adjust our aws bucket for CORS which can be a bit of a snag. These links should should help you in the right direction though!
https://coderwall.com/p/ub8zug/serving-web-fonts-via-aws-s3-and-cloudfront
Amazon S3 CORS (Cross-Origin Resource Sharing) and Firefox cross-domain font loading
Did you try to use plugins like webpack-s3-plugin
You can define rules for all assets you need.
And of cause you'll have to eject CRA or use something kind of react-app-rewired or rescripts.

Deploying Create React App to a subdirectory but make API calls to parent path

I'm deploying my Create React App to a specific path in a larger non-React webapp. For example, I will say the webapp path is www.example.com and the React app is deployed at www.example.com/react/
I have done this by setting the "homepage" property in package.json of the React app to "homepage": "/react", which does properly serve the static files from the /react/ path on my server.
However, when I make API calls from my react app, they go to /react/api/etc instead of /api/etc.
I can configure axios to use a hardcoded base path of www.example.com, but I deploy this to multiple environments with different URLs and need a solution that doesn't rely on a hardcoded value.
I could also write a workaround on the server side, but it would be less clean / mess with my logging and request statistics.
I would love a clean solution if one exists.
what if you used the window.location property in your axios config object:
{
baseURL: `${location.hostname}/api/` // or window.location.hostname
}

Cache busting with CRA React

When I updated my site, run npm run build and upload the new files to the server I am still looking the old version of my site.
Without React, I can see the new version of my site with cache-busting. I do this:
Previous file
<link rel="stylesheet" href="/css/styles.css">
New file
<link rel="stylesheet" href="/css/styles.css?abcde">
How can I do something like this or to achieve cache busting with create react app?
There are many threads in the GitHub of create react app about this but no one has a proper/simple answer.
EDIT: create-react-app v2 now have the service worker disabled by default
This answer only apply for CRA v1
This is probably because of your web worker.
If you look into your index.js file you can see
registerServiceWorker();
Never wondered what it did? If we take a look at the file it got imported from we can see
// In production, we register a service worker to serve assets from local cache.
// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on the "N+1" visit to a page, since previously
// cached resources are updated in the background.
// To learn more about the benefits of this model, read {URL}
// This link also includes instructions on opting out of this behavior.
If you want to delete the web worker, don't just delete the line. Import unregister and call it in your file instead of the register.
import { unregister } from './registerServiceWorker';
and then call
unregister()
P.S. When you unregister, it will take at least one refresh to make it work
I had the same issue when I use create-react-app ( and deploy to heroku). It keeps showing the old version of my app 😡.
I found the problem seems to be on the browser side, it caches my old index.html with its outdated js bundle
You may want to add the following to your server side response header
"Cache-Control": "no-store, no-cache"
or if you are also using heroku create-react-app-buildpack, update the static.json file
"headers": {
"/**": {
"Cache-Control": "no-store, no-cache"
}
}
I think in this way you can still keep that poor service worker 😂, and the latest content will be shown on the N+1 load (second refresh)
Hope this helps...
As mentioned by some of the previous answers here, both the service worker and the (lack of) cache headers can conspire against you when it comes to seeing old versions of your React app.
The React docs state the following when it comes to caching:
Using Cache-Control: max-age=31536000 for your build/static
assets, and Cache-Control: no-cache for everything else is a safe
and effective starting point that ensures your user's browser will
always check for an updated index.html file, and will cache all of
the build/static files for one year. Note that you can use the one
year expiration on build/static safely because the file contents
hash is embedded into the filename.
As mentioned by #squarism, older versions of create-react-app defaulted to opt-out of service worker registration, while newer versions are opt-in. You can read more about that in the official docs. It's quite a straightforward process to match you configuration to the latest template if you started with an older version of create-react-app and you want to switch to the new behaviour.
Related questions:
How to avoid caching for create-react-app
ReactJS: How to prevent browser from caching static files?
how to clear browser cache in reactjs
If your problem is with resources statically referenced in index.html, such as .css files or additional .js files (e.g. configuration files), you can declare a React environment variable, assign a unique value to it and reference it in your index.html file.
In your build script (bash):
REACT_APP_CACHE_BUST={e.g. build number from a CI tool} npm run build
In your index.html:
<link rel="stylesheet" href="%PUBLIC_URL%/index.css?cachebust=%REACT_APP_CACHE_BUST%" />
The variable name has to start with REACT_APP_. More about environment variables in React: https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables.
It appears that they changed from opt-out to opt-in with regards to the service worker. Here's the commit that changed the README and it has examples similar to Kerry G's answer:
https://github.com/facebook/create-react-app/commit/1b2813144b3b0e731d8f404a8169e6fa5916dde4#diff-4e6ec56f74ee42069aac401a4fe448ad

Resources