React S3+Cloudfront Cache Invalidation issues - reactjs

For the project, we tried to deploy the front-end React static files by using AWS S3 + cloudfront.
It worked at the first time, but there was an issue that even though we updated with new build, some of the contents were not updating.
For the updates, we tried using invalidation method in Cloudfront and set /index.html. However, it didn't work properly and didn't load the updated build file so we also tried to invalidate assets files and met this problem.
Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "text/html". Strict MIME type checking is enforced for module scripts per HTML spec
Is there a way to cancel the invalidation that we already did or fix this issue?

Related

Angular - Failed to load module script:

I have angular 8 front end application in production and its Failed to load module script: The server responded with a non-JavaScript MIME type of "text/html". Strict MIME type checking is enforced for module scripts per HTML spec.
This issue is happening only in production build that too not always , able reproduce only sometimes.
main-es2015.fcc7123d15fd9c113b00.js:1
vendor-es2015.d8d7d81cc2b06ece8c91.js:1
How do i fix it.?
Are you using serviceWorker?
If so you have to add inside angular.json "serviceWorker": true for the configuration that you are using.
I would like to share my experience with the same issue I was facing in the organization where I'm working.
I had an Angular 9 application and when I deployed to Stage environment, I got three errors in my console which showed as "module not loaded due to Mime type". This was working fine in all other environment and after much struggle, it was found that the files under the website were not having access. E.g. When you deploy an Angular application, you will get index.html file and many other js files. The website had permission issues. The site was hosted in the Rackspace and the FireWall was not configured to have access to the files right under the website.
Once the below access was provided, the app started working.
/assets*
/*.css
/*.js
/*.ico
/*.html
The only difference I see with your problem is that you have mentioned it is working sometimes.
There is another post Blocked because of a disallowed MIME type (“text/html”) : Angular 8 deployed on tomcat 9.0.30 fails to serve the assets try the solution based on base reference as those js files are not served/loaded
I hope this might help someone.

AngularJS issue: $sce:insecurl despite $sce.trustAsResourceUrl

I have a set-up using templates from my CDN, that usually works fine but periodically I get this error:
ng-error: Error: [$sce:insecurl] http://errors.angularjs.org/1.7.5/$sce/insecurl?p0=https%3A%2F%2Fcomplicemail-herokuapp-com.global.ssl.fastly.net%2Fstatic%2Ftemplates%2Fviewschedule.a15ce4bf.html
I grepped the codebase for viewsched, and literally the only two places in the code where that template are my precache list in my service worker, and this line in the angularjs file:
$scope.scheduleTemplateUrl = $sce.trustAsResourceUrl('/templates/viewschedule.html')
Gulp turns that line into the one that references the CDN:
$scope.scheduleTemplateUrl = $sce.trustAsResourceUrl('https://complicemail-herokuapp-com.global.ssl.fastly.net/static/templates/viewschedule.a15ce4bf.html')
I know that part's working because the insecurl error shows the CDN url.
My first guess that the issue is something like "for whatever reason (eg shoddy internet) the browser couldn't connect with the CDN at that moment and failed to fetch the file, giving some sort of HTTP response code that AngularJS considers insecure. But I think that would produce this issue (which I also periodically get)
ng-error: Error: [$templateRequest:tpload] http://errors.angularjs.org/1.7.5/$templateRequest/tpload?p0=https%3A%2F%2Fcomplicemail-herokuapp-com.global.ssl.fastly.net%2Fstatic%2Ftemplates%2Ftimer%2Fuser-other.27734af8.html&p1=-1&p2=
Any ideas? Also interested in ideas for how to more gracefully handle the tpload error situation in cases like this where the url is correct but the internet just conked out at that moment.

Error while deploying react based SSR app, using firebase-functions

I am trying to deploy my SSR app in Firebase originally forked from, after doing some modification in the app.
Which works fine when I do sudo firebase serve --only functions,hosting but throwing error when I do firebase deploy.
The reproducible repo has a package.json.
I am using the public directory as my function directory as well.
However, even if I am using a different function directory for my cloud functions, I see the same errors.
Function failed on loading user code. Error message:
Code in file index.js can't be loaded. Is there a syntax error in your code?
Detailed stack trace: TypeError: c(...) is not a function
at Object.<anonymous> (/user_code/assets/app.server.js:1:28950)
at Object.module.exports.n (/user_code/assets/app.server.js:1:29283)
...
Functions deploy had errors.
To continue deploying other features (such as database), run:
firebase deploy --except functions
Error: Functions did not deploy properly.
It is possible, but you cannot serve static assets with cloud functions. You need a mix of firebase functions and firebase hosting.
The guys at Firebase already thought on this and you also have an implementation available.
Check the following documentation:
Overview
Dynamic Content
Code Example
Youtube Video
Note: There is a delay that you need to take into consideration when using cloud functions.
When a new instance handles its first request, the response time suffers, which is called a cold start
More info
The problem is that firebase hosting only supports SPAs, which means that SSR is out of the picture, you need to run your SSR server in a different env where you can run nextJS, or if you're using a static page generator you could upload the files directly compromising on the ability to refresh the content, although, I'm sure a solution with cloud functions and gatsby is feasable.
Tl;DR: You won't get SSR out of Firebase Hosting

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

react + webpack - pass POST data to build

Coming from a PHP background, I used to have an index.php which does two things:
serve the webpage if no parameters were set;
or serve JSON data when a specific POST parameter was included in the request.
Something like this:
// -- index.php
<?php
if ($_POST["some_parameter"]) {
...
echo json_encode(someArrayData);
exit(0);
}
?>
<html>
...
</html>
I have built the complete frontend application with npm, webpack, webpack-dev-server, and react. Having completed the first part, how can I effectively serve JSON data instead of HTML when a request includes a specific POST parameter?
I can see 2 ways of doing this:
Build the frontend as usual and everytime I build the bundle, modify index.html, inject my PHP code in it, and rename it to index.php. I then would have to run this folder via apache or nginx, so I'd be able to run the index.php script. This method is downright ugly and is probably the worst way to do it.
Run a separate PHP server which just serves data or redirects to the static webpack-generated build. All requests should then start from this server, and this server determines whether to serve data or redirect to the frontend. The problem comes to neatly passing the POST data received from the request to the static react app. As far as I know, the only way to do this would be to include a URL (GET) parameter to the redirect and manually parse it with javascript on the frontend. This is a dirty solution, in my opinion.
So, to summarize:
I need an efficient way to get POST data in a react/webpack/webpack-dev-server environment.
It should work with my hot-module-replacement dev setup.
I'm fine with switching to a node-based backend like express.
There shouldn't be any ajax involved in the static react app.
Any ideas? There has to be a way to do this properly.
UPDATE: I solved this by simply copying an index.php from my source directory to my build directory via the webpack config. I serve the build folder to a PHP server and keep a webpack --watch building my source.
I lose built-in features like auto-reload and css injection, but it's worth the convenience of not having to implement SSR for a very simple task (getting a single POST variable).
For anyone interested, I also added 2 npm scripts:
npm run start runs my original webpack-dev-server with hot-reload, serving static content including a static index.html file
npm run static runs the webpack --watch which copies the index.php file to the build directory
This lets me have hot-reloading when developing frontend, and allows POST data fetching when programming logic.
It's easy, convenient, and works on most web hosting providers.

Resources