Preloading animation for React webpack bundle - reactjs

I have a single page webapp, which is about 300Kb big. It gets bundled with webpack and uses React/Redux.
How do I put a small loading spinner upfront until the page is loaded? I can image
putting the style and css into the static index.html
using an async loader like krux/postscribe

One way would be to insert the loading animation in the index.html
e.g.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div id="content">
<div id="loader" />
</div>
<script src="build/app.js"></script>
</body>
</html>
Then after the bundle.js is loaded it will render in the content and the loading animation will disappear.
EDIT:
Another method is to use a progressive webapp.
https://developers.google.com/web/updates/2015/10/splashscreen
However this feature might only be available in modern browsers, which is why the first approach should be used as a fallback method.
The benefit however is, that if your app is offline it will still play
the loading animation and can give specific error messages.

I also encountered with this question with one exception: I wanted to display a loading progress bar. I ended up writing a webpack plugin and a custom asset bootloader. Check out my demo project repository.
Here is the result:

Related

How to call Branch listeners on React.js Cordova app

I am using a React.js app in a Cordova framework.
As the docs are not really clear, I would like to understand how to call a Branch.io listener in a my app, so that I can capture where the Branch.io link was clicked, by whom and what exact URL was clicked. There must be a way to call the Branch.io events from React itself (otherwise, how can you be listening to the event inside the app?). I tried the following in my index.js file but was not successful because the build of the React app failed (as cordova is only available during runtime).
import {Branch} from "branch-cordova-sdk"
Any help would be appreciated! Thanks in advance!
For anybody else arriving at this page:
If you are trying to generate and access branches from Branch.io in your React.js app (not React native) and you have embedded it into a Cordova app, you have to follow these documentation: https://help.branch.io/developers-hub/docs/web-basic-integration
As quick bullet points:
You have to call the branch in your index.html file, as mentioned in the docs:
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title></title>
<script>
// load Branch
(function(b,r,a,n,c,h,_,s,d,k){if(!b[n]||!b[n]._q){for(;s<_.length;)c(h,_[s++]);d=r.createElement(a);d.async=1;d.src="https://cdn.branch.io/branch-latest.min.js";k=r.getElementsByTagName(a)[0];k.parentNode.insertBefore(d,k);b[n]=h}})(window,document,"script","branch",function(b,r){b[r]=function(){b._q.push([r,arguments])}},{_q:[],_v:1},"addListener applyCode autoAppIndex banner closeBanner closeJourney creditHistory credits data deepview deepviewCta first getCode init link logout redeem referrals removeListener sendSMS setBranchViewData setIdentity track validateCode trackCommerceEvent logEvent disableTracking".split(" "), 0);
// init Branch
branch.init('key_live_YOUR_KEY_GOES_HERE');
</script>
</head>
<body>
</body>
</html>
Then, on your React.js app, add the branch listener directly:
function onResume() {
let branch = window.branch;
// Whatever else you want to do when you receive your branch information.
}
Just define what you want to do with your branch from there onwards.

How to make Google Auto Ads work with react SSR application

I want to use the Google Adsense Auto-Ads with my react application. The react application uses SSR and I have added the code that Google provided me to the head section of the template as shown below.
export default ({ markup, css }) => {
return `<!doctype html>
<html lang="en">
<head>
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9999999999999999" crossorigin="anonymous"></script>
<meta charset="utf-8">
<meta
name="viewport"
content="minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no"
>
<title>Teach Learn Game</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:100,300,400">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<style>
a{
text-decoration: none;
color: #bb4d00
}
</style>
</head>
<body style="margin:0">
<div id="root">${markup}</div>
<style id="jss-server-side">${css}</style>
<script type="text/javascript" src="/dist/bundle.js"></script>
</body>
</html>`;
};
When at the site, I have checked the html code using Chrome tools. I can see the line in the code but unfortunately I have been declined by the Google Adsense review saying I need to Fix some things.
The message from Google specifying the issue is:
We couldn’t find the code on your site. This is because the code is either missing or incomplete, or because the URL of your site is incorrect. Learn more.
I have removed the requirement to login which was an earlier problem and I have a proper google account.
I did see another Stack Overflow issue where it was stated that window.adsbygoogle is to be used with React but it seemed that the problem was dealing more with specifying ad units and the implementation of the window.adsbygoogle was in a component class. As I am using Auto Ads I would not expect that would apply but maybe I am mistaken. If so, how would I change the code?
In any case, appreciate if anyone with experience with getting initial acceptance for Google Auto Ads can assist. If you provide code appreciate if you could use functional components as I am not very up on class components and the use of componentDidMount as most of the examples seem to be using.
Link to my site: https://tlgamer.herokuapp.com/
Adsense will look for Adcode in herokuapp.com instead of tlgamer.herokuapp.com that is why message from Google was "We couldn’t find the code on your site.", You can not monetize a subdomain if you do not own the main domain. Switch your SSR app to a top-level domain and re-apply for Adsense.

Google Crawler in Search Console can't found routes in React using Github Page

My problem is Crawl in Google Search Console can't found sub-routes in React.
The URL is https://huynhsamha.github.io/crypto, and crawler can fetch and render homepage (route /) and static files such as /robots.txt, /favicon.ico, but it can't found the sub-routes, which are rendered by React, (SPA, using Redux), such as /algorithm/sha256. Example, https://huynhsamha.github.io/crypto/algorithm/sha256 can't found by Crawler but it can be accessible.
This is my screenshot in Google Search Console I've tried.
Who can explain why and how to fix my problem? I'm using react-router-dom with react-redux My repository on github here
Edit 1
I've also tried the answer https://stackoverflow.com/a/53966338/8828489 in this question, but not working. I've added script in index.html (https://github.com/huynhsamha/crypto/blob/gh-pages/index.html), but search console can't still found, so it also can't render any error on screen.
Edit 2
I've also tried the answers https://stackoverflow.com/a/54040745/8828489 and https://stackoverflow.com/a/54048119/8828489 in this question, but not working. I've created 404.html file and add scripts as the answer instructs but it didn't also work.
Edit 3
I've also tried the answer https://stackoverflow.com/a/54044148/8828489 in this question by creating a simple sitemap.xml, googlebot can find this file and discover all URLs I defined in sitemap. But it also cannot fetch and render URLs mentioned.
I found that when i opened https://huynhsamha.github.io/crypto/algorithm/sha256, I actually received a 404 as a response. I think your workaround for hosting SPA on GitHub using the 404.html is the issue here. While us humans see your app being served on our browser correctly, googlebot doesn't care and just look at the response code and see that it has received a 404. You'll need a different workaround that doesn't involves using the 404.html as the entry point to your app directly.
Try following this workaround by rafrex instead, it redirects the browser to index.html using the 404.html while keeping the original route, it claims that googlebot register that as a 301 instead of a 404, for your case that means adding these changes below to your site, pay attention to the script below the <!-- ------Single Page Apps GitHub Pages Workaround------ -->:
<!-- 404.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Cryptography</title>
<!-- ------Single Page Apps GitHub Pages Workaround------ -->
<script type="text/javascript">
// Single Page Apps for GitHub Pages
// https://github.com/rafrex/spa-github-pages
// Copyright (c) 2016 Rafael Pedicini, licensed under the MIT License
// ----------------------------------------------------------------------
// This script takes the current url and converts the path and query
// string into just a query string, and then redirects the browser
// to the new url with only a query string and hash fragment,
// e.g. http://www.foo.tld/one/two?a=b&c=d#qwe, becomes
// http://www.foo.tld/?p=/one/two&q=a=b~and~c=d#qwe
// Note: this 404.html file must be at least 512 bytes for it to work
// with Internet Explorer (it is currently > 512 bytes)
// If you're creating a Project Pages site and NOT using a custom domain,
// then set segmentCount to 1 (enterprise users may need to set it to > 1).
// This way the code will only replace the route part of the path, and not
// the real directory in which the app resides, for example:
// https://username.github.io/repo-name/one/two?a=b&c=d#qwe becomes
// https://username.github.io/repo-name/?p=/one/two&q=a=b~and~c=d#qwe
// Otherwise, leave segmentCount as 0.
var segmentCount = 1;
var l = window.location;
l.replace(
l.protocol + '//' + l.hostname + (l.port ? ':' + l.port : '') +
l.pathname.split('/').slice(0, 1 + segmentCount).join('/') + '/?p=/' +
l.pathname.slice(1).split('/').slice(segmentCount).join('/').replace(/&/g, '~and~') +
(l.search ? '&q=' + l.search.slice(1).replace(/&/g, '~and~') : '') +
l.hash
);
</script>
</head>
<body>
</body>
</html>
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<meta name="description" content="Cryptography Algorithms: Secure Hash Algorithm (sha256, sha512, ...), Message Digest Algorithm (md5, ripemd160), HMAC-SHA, HMAC-MD, pbkdf2, Advanced Encryption Standard (AES), Triple Data Encryption Standard, (TripleDES, DES), RC4, Rabbit, ...">
<meta name="keywords" content="crypto, algorithms, secure hash, sha, sha512, sha256, message digest, md5, hmac-sha, aes, des, tripledes, pbkdf2, rc4, rabbit, encryption, descryption">
<meta name="author" content="huynhsamha">
<!-- Open Graph -->
<meta property="fb:app_id" content="440168923127908">
<meta property="og:url" content="https://huynhsamha.github.io/crypto">
<meta property="og:title" content="Cryptography Algorithms">
<meta property="og:description" content="Cryptography Algorithms: Secure Hash Algorithm (sha256, sha512, ...), Message Digest Algorithm (md5, ripemd160), HMAC-SHA, HMAC-MD, pbkdf2, Advanced Encryption Standard (AES), Triple Data Encryption Standard, (TripleDES, DES), RC4, Rabbit, ...">
<meta property="og:type" content="website">
<meta property="og:image" content="%PUBLIC_URL%/img/main.jpeg">
<meta property="og:site_name" content="Cryptography">
<meta property="og:locale" content="vi_VN">
<!-- Twitter Card -->
<meta name="twitter:card" content="summary">
<meta name="twitter:site" content="#huynhsamha">
<meta name="twitter:creator" content="#huynhsamha">
<meta name="twitter:url" content="https://huynhsamha.github.io/crypto">
<meta name="twitter:title" content="Cryptography Algorithms">
<meta name="twitter:description" content="Cryptography Algorithms: Secure Hash Algorithm (sha256, sha512, ...), Message Digest Algorithm (md5, ripemd160), HMAC-SHA, HMAC-MD, pbkdf2, Advanced Encryption Standard (AES), Triple Data Encryption Standard, (TripleDES, DES), RC4, Rabbit, ...">
<meta name="twitter:image:src" content="%PUBLIC_URL%/img/main.jpeg">
<!--
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<link rel="author" href="//github.com/huynhsamha">
<link rel="canonical" href="//huynhsamha.github.io/crypto">
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<link href="//fonts.googleapis.com/css?family=Open+Sans:400,600,700&subset=vietnamese" rel="stylesheet">
<link rel="stylesheet" href="%PUBLIC_URL%/css/bootstrap.min.css">
<link rel="stylesheet" href="%PUBLIC_URL%/lib/font-awesome/css/font-awesome.min.css">
<!-- ------Single Page Apps GitHub Pages Workaround------ -->
<script type="text/javascript">
// Single Page Apps for GitHub Pages
// https://github.com/rafrex/spa-github-pages
// Copyright (c) 2016 Rafael Pedicini, licensed under the MIT License
// ----------------------------------------------------------------------
// This script checks to see if a redirect is present in the query string
// and converts it back into the correct url and adds it to the
// browser's history using window.history.replaceState(...),
// which won't cause the browser to attempt to load the new url.
// When the single page app is loaded further down in this file,
// the correct url will be waiting in the browser's history for
// the single page app to route accordingly.
(function(l) {
if (l.search) {
var q = {};
l.search.slice(1).split('&').forEach(function(v) {
var a = v.split('=');
q[a[0]] = a.slice(1).join('=').replace(/~and~/g, '&');
});
if (q.p !== undefined) {
window.history.replaceState(null, null,
l.pathname.slice(0, -1) + (q.p || '') +
(q.q ? ('?' + q.q) : '') +
l.hash
);
}
}
}(window.location))
</script>
<title>Cryptography</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
<script src="%PUBLIC_URL%/js/jquery-3.3.1.slim.min.js" type="text/javascript"></script>
<script src="%PUBLIC_URL%/js/popper.min.js" type="text/javascript"></script>
<script src="%PUBLIC_URL%/js/bootstrap.min.js" type="text/javascript"></script>
<!-- Google Adsense -->
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
</body>
</html>
More info and discussions on GitHub's support for single page app here.
I poked around in your source code and don't see anything alarming; however, I found a few posts about similar issues (1) (2). The second seems particularly helpful, so I'll repeat it here. Shout out to #Zerotorescue on Reddit.
Open Google Search Console and go to Crawl -> Fetch as Google and do a fetch and render.
Add this to your site, either as a part of tag in your HTML file or as part of the bundle:
https://gist.github.com/mstijak/715fa2dd3f495a98386c3ebbadbabb8c
I recommend the former since that makes it easier to change if you need to make it more readable (no need to recompile your app).
Push this to your site and then do another fetch and display. The error preventing Google from running your app will now show. The search console resolution is pretty low so you may have to increase the font-size of the error and fetch again. Don't worry, Google doesn't mind repeated calls.
You'll probably find that Google's crawler can't process your code because you're using some ES6 feature it doesn't support. You can fix this by polyfilling. I've tried a couple of things such as https://polyfill.io/ which turned out to not really support Googlebot and while it might sometimes work, it is pretty unreliable. Instead I recommend using babel-polyfill. It will increase your bundle size a little bit for everyone but in my experience it provides the widest browser support with a minimal headache. Just turn it on and you're done.
If you're using create-react-app this is the polyfills.js file I use that you could copy:
https://github.com/WoWAnalyzer/WoWAnalyzer/blob/2c67a970f8bd9026fa816d31201c42eb860fe2a3/config/polyfills.js#L1
Notice there are a lot of comments explaining all the issues the polyfill service introduce that you won't have to deal with if you use babel-polyfill.
Because, react app is onepage web, You need a sitemap file, you can find it how to make a one here ,too make a 404 page, and every route add property that has a anchor
like to
<a title="This my Route One" href="https://myreactapp/routeOne" alt="Route One"/>
The problem is that you're using a 404 page to capture incoming traffic to routes other than /. This means those routes serve a 404 status code (you can see this if you open Network in dev tools and try to visit one of those deep URLs). Google sees a 404 status in the response header and just gives up right away. You probably noticed that the "Not Found" message in Webmaster Tools popped up super-fast.
On a normal server, you would capture those routes and return a successful status code like 200 or 301 and Google would continue crawling. However, because you're using GitHub pages, you need to hack your way around it.
You should be able to do this by setting up an instant redirect from that 404 template to your index template. Browsers interpret instant redirects as 301s. To do this, replace the contents of your 404.html with something like this:
<html>
<head>
<script>
sessionStorage.redirect = location.href; // we'll use this later
</script>
<meta http-equiv="refresh" content="0;URL='/crypto'">
</head>
<body></body>
</html>
Just make sure the file-size of that 404.html is greater than 512b or IE will discard it (damn M$...).
Lastly, you'll need to make sure your index.html captures the original route. To do so, use a script like this in the head of your index.html:
<script>
(function(){
var redirect = sessionStorage.redirect; // remember me?
delete sessionStorage.redirect;
if (redirect && redirect != location.href) {
history.replaceState(null, null, redirect);
}
})();
</script>
For reference, I stole this clever hack from:
https://www.smashingmagazine.com/2016/08/sghpa-single-page-app-hack-github-pages/
I also, do not see anything alarming in your code (although I don't think you need the baseUrl in your <Route /> - though I could be wrong, and don't think that's the issue, but it may be worth eliminating if unnecessary).
Just a guess but looking at the networks tab as I bounced around the links, I noticed the service worker. I am, admittedly, not super savvy when it comes to service workers (yet!), however googling a bit revealed that google crawlers do not yet support service workers as asserted in this article, this article, and by google.... I also noticed that if I run a Lighthouse test on one of the links I reached via in-app navigation (for instance I click on the /algorithm tab from the nav on the homepage and then run a Lighthouse test) I get the following errors:
There were issues affecting this run of Lighthouse: Chrome extensions
negatively affected this page's load performance. Try auditing the
page in incognito mode or from a Chrome profile without extensions.
and more interesting:
Lighthouse was unable to reliably load the page you requested. Make
sure you are testing the correct URL and that the server is properly
responding to all requests. Status code: 404.
...despite clearly seeing it rendered in the browser. Seems suspect. So, if that is part of how navigation is happening (seems it likely is based on the registerServiceWorker.js file in your repo lol), it may be the cause of your links not being found/followed.

grunt serve VS opening index.html in browser

I'm using Yeoman and the angular-fullstack generator to bootstrap an angular app. When I do grunt serve or grunt serve:dist everything works as expected.
Now the question is, when I open the index.html file directly in the browser, isn't it supposed to work equally?
So I have a hard time understanding whats tasks grunt is executing here to make it work. Or maybe I am missing something else.
The console tells me:
GET file:///app/8d57a97f.app.css net::ERR_FILE_NOT_FOUND
GET file:///app/47ab0f3e.vendor.js net::ERR_FILE_NOT_FOUND
GET file:///app/01b9b8a8.app.js net::ERR_FILE_NOT_FOUND
The generated index.html looks something like this:
<!doctype html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<base href="/">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" href="app/8d57a97f.app.css"/>
</head>
<body ng-app="myApp">
<!-- some functionality... -->
<script src="app/47ab0f3e.vendor.js"></script>
<script src="app/01b9b8a8.app.js"></script>
</body>
</html>
The reason why I do this:
I try to run the angular app with phonegap on an android device. When I load it to the android mobile, the screen remains blank. So I opened it in the browser and got the same result.
So this is my first attempt to solve this issue.
The problem was the <base href="/"> in the header.
Explanation can be found here (Loading local file in browser referenced css or js).

JQuery mobile: test offline

I am new in JQuery Mobile. I really like it but I have 2 basic questions:
1- Can I test the app OFFLINE in my iPhone?
I know how to see the app when I am with an Internet connection even how to create the icon. But I don't see how to see the app i I don't have an Internet connection.
2- I suppose I can sent the html and css made with jQuery Mobile to Apple as any app. And it will work offline. Is that right?
Is there anyone with experience who have done apps with JQuery Mobile and are working in the app store?
Yes, you can have a jQuery Mobile page completely offline. Download the necessary libraries to your device. For the example I used the following
jquery-1.8.0.min.js
jquery.mobile-1.2.0.min.js
Additionally you need the jQuery Mobile CSS structure file
jquery.mobile.structure-1.2.0.min.css
Then use the theme roller to create your own CSS (or without changes just use the default jQuery CSS) and download it including the icon sets to your device. For the example I used this CSS name
taifun.min.css
The icon sets are stored in the subdirectory /images.
example code
<!DOCTYPE html>
<html>
<head>
<title>Offline</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="taifun.min.css" />
<link rel="stylesheet" href="jquery.mobile.structure-1.2.0.min.css" />
<script src="jquery-1.8.0.min.js"></script>
<script src="jquery.mobile-1.2.0.min.js"></script>
</head>
<body>
<div data-role="content">
<h1>I'm a jQuery Mobile offline page</h1>
<ul data-role="listview">
<li>Acura</li>
<li>Audi</li>
<li>BMW</li>
<li>Cadillac</li>
</ul>
</div><!--/content -->
</body>
</html>
screenshot HTC Desire
#Brice Favre is right - testing 'offline' could be achieved by hosting your app on a LAN and accessing it using your iPhone through Wifi.
If you 'host' the app using e.g. PhoneGap, and include all the libaries (jQuery, jQuery Mobile) and CSS as part of your application, then your app will function just fine without an Internet connection - many apps work this way. See this PhoneGap tutorial.

Resources