Friday, April 17, 2020

Your First (rudimentary) PWA in Seven Steps


Introduction, audience, and scope

This is a very, very basic tutorial. I will refrain from even calling it ‘bare-bones’ because that skeleton would be missing the metacarpals and a femur, so to speak.

The goal, or use case, is simply to get the app to pass the PWA audit in Chrome and make the app downloadable to a user’s machine, should the user decide they are better off using an offline version of the application.

To begin with, you should already have written and fully debugged a dirt-simple, front-end only HTML/JavaScript app that does not require any external resources (it does not connect to an API for data, for example).

To see the example I used, go to here .

Besides some basic HTML and JavaScript, some introductory knowledge of service workers is a prerequisite for this tutorial. PWA is where you will really start of suffer from and then master service workers. If you are absolutely new to service workers, stop here and go do one or two tutorials that are focused just on service workers. Then come back.

Please note that I am using a Windows 10 machine and the Chrome browser for all of this. If you are following the steps of this tutorial and getting different results, first check to see if the issue may be that you are using a different setup.

Make your app visible to Chrome

I am using Chrome’s Audit feature to get started on the PWA version of the app (Audit comes with Chrome - just open Chrome and hit F12 to see the dev tools; Audits is one of the tabs across the top). In order for Audit to see your app, and then later for service workers to function properly, your app has to be in a HTTP/HTTPS document. You cannot just be running your app on local host. There’s probably half a dozen better ways to go about meeting this requirements, but what I did to accomplish this was just to host my app on GitHUB pages.

(For more of a nuts and bolts guide to actually setting up a GitHub Pages website manually without all the bells and whistles, go to my earlier post).

NOTE: If you opt for GitHub pages, always use full reference paths as opposed to partial paths. Absolutely make sure to name the main file “index.html” or GitHub Pages won’t work in your browser.

Audit your app and clean up failures

Once you have reached the point where you can view your app the in Chrome web browser as a HTTP/HTTPS doc, you are ready to run an audit in Chrome and figure out where to go from here.
Click F12 and that will open the Chrome dev tools. Up at the top where it says “Elements,” “Console,” “Sources,” etc,. click on the “Audit” tab. On the “Audit” tab, click the “Generate report” button.

There will probably be lotsa red telling you how miserably your site fails to meet basic industry standards.

At this point you could easily ignore the components of the Audit that do not have to do directly with PWA and just move on. But loose ends drive me batty so I cleaned them up. Just google each statement and patch up your HTML accordingly.

Add a manifest.json file

PWA requires a ‘manifest.json’ file in the root directory. You have to title the manifest ‘manifest.json’ and save it as a .json file.

The manifest you are starting out with in this tutorial is very minimal. Other more advanced tutorials will show you how to do more with the manifest and more with logos. For now we are just keeping things dirt-simple.

Your manifest should look like this (fill in what you want for ‘name,’ ‘short_name,’ and the colors):

  {
  "name": "<the name of your app>",
  "short_name": "<the name of your app>",",
  "icons": [
    {
      "src": “images/192_icon.png",
      "type": "image/png",
      "sizes": "192x192"
    },
    {
      "src": "images/512_icon.png",
      "type": "image/png",
      "sizes": "512x512"
    }
  ],
  "start_url": "https://<username>.github.io/index.html",
  "display": "standalone",
  "background_color": "<the color you want>",
  "theme_color": "<the color you want>"
}

In a typical PWA, there are actually more than just the two icon/icon sizes used. But these two – 192 px and 512 px - are the bare minimum to get a PWA up and running, and this is a bare-minimum tutorial. In fact, I just went out and googled “free test icons,” one for 192 pix and one for 512 px. I copied and pasted them to good ol’ Paint, saved them as jpegs, then uploaded them to a ‘images’ folder in the root directory of the GitHub page. 

Create an offline version of the app

Just create a copy of the index.html file in the root directory. Title this new file ‘offlineApp.html.’
In a full PWA application, something that is beyond the scope of this tutorial, the offline version of the app is part of what allows PWA to turn your app into something that can seamlessly transition between an online and an off-line experience. It's a big deal. But given the very limited scope of this tutorial, just create and rename the copy of index.html for now. Consider it a stub where the future offline version of the app will go when you know more about PWA.

Create the Service Worker

Now, create the service-worker.js file in the root directory. Here is my code for my service-worker.js file:

  const myCache = 'static-cache';
  const pageToCache = [ '/offlineApp.html' ];

  self.addEventListener('install', function(event) {
    event.waitUntil(
      caches.open(myCache)
      .then(function(cache) {
        return cache.addAll(pageToCache);
      })
    );
  });

  self.addEventListener('fetch', function(event) {
    event.respondWith(
      caches.match(event.request)
      .then(function(response) {
        return response || fetchAndCache(event.request);
      })
    );
  });

  function fetchAndCache(url) {
    return fetch(url)
    .then(function(response) {
      // check for valid response
      if (!response.ok) {
        throw Error(response.statusText);
      }
     return caches.open(myCache)
      .then(function(cache) {
        cache.put(url, response.clone());
        return response;
      });
    })
    .catch(function(error) {
      console.log('Request failed:', error);
      // offline 404 page really needs  go here but I have not bothered yet
    });
  }

Reference service-worker.js and manifest.json in index.html

Our goal, again, is a very limited one. We just want to use PWA to let the user download the app from the page where the app is hosted.

Add the following to the header section of your HTML:

  <link rel=”manifest” href=”https://< username>.github.io/manifest.json” />

NOTE: Always use ‘https’ in your links and not ‘http,’ otherwise you will create what is known as a cross-origin error. This is because GitHub resources always use the secure ‘https’ protocol.

Go to your index.html page and add a <script></script> section. Add the following code:

  if ('serviceWorker' in navigator) {
   window.addEventListener('load', () => {
    navigator.serviceWorker.register('/service-worker.js')
     .then((reg) => {
      console.log('Service worker registered.', reg);
     });
    });
  }

Test

That’s pretty much it. If you run your app in your Chrome browser, check out the three vertical dots icon. There should now be an option to install a stand-alone version of your app. Congrats – you’ve got your first PWA up and running!

Troubleshooting

App not working on other browsers?

Not all browsers support the web app manifest the same way Chrome does. But you want your app to work on all browsers if possible. Try updating your meta-tags in index.html to help out other browsers. Add the following to the header section of your index.html file:
  <meta name = “apple-mobile-web-app-title” content=”myApp” >
  <meta name = “apple-mobile-web-app-status-bar-style” content=”blue” >
  <meta name = “apple-mobile-web-app-title” content=”myApp” >

 


Follow these steps to create a GitHub Pages website without having to download anything

Step one is that you need craft and debug an HTML file locally on your own machine. Nothing fancy here – just open a text editor like NotePad and get rolling. An example of just such an app is here. You can use that if you want, but I would suggest you do this with your own code so you have the satisfaction of seeing your own creation as a web page anyone can access.

 Step two is that you store the file in a folder on your machine and rename it “index.html.” If it is any other name, it will not work on GitHub Pages.

Step three is make sure you have an account on GitHub. As of writing, this is totally free and requires no special software on your machine to get an account and manipulate GitHub right in your browser (stuff like Git that you have to download onto your machine can be learned later and are not necessary for this tutorial).

 Step four is create a repository on your GitHub account. Your webpage is basically just going to be a repository on your GitHub account. Just navigate to your GitHub account and click to create a new repository (aka “repo”). Just make sure the repo name is your GitHub user name plus “github.io” when you name it. My user name is olddognewtrix123, so when I made a repo that is supposed to actually be a webpage, I went on to my GitHub account, and clicked to create a new repo. When I was prompted to name the repo, I called it “olddognewtrix123.github.io.” If you do not name your repo correctly, all you will have created is just another GitHub repository. Which is great, but you won’t be able to hit it from your browser like a web page. So follow the exact naming convention. Leave the “Public” radio button selected. You can leave the “Initialize with ReadMe” checkbox unselected – it is not necessary. Now click the green Create Repo button.

 Step five is to click the Upload File button on the repository’s page. Select your index.html file from the folder on your machine and complete the upload. Fill out the comment fields and click the green Commit Changes button. You can repeat step three for any other files that your index.html file needs to run, like if you have a separate style sheet.

 Step six is super important and not a lot of tutorials mention it: you gotta make sure index.html has a ref tag, it is using the absolute path and not the relative path. So, click on the index.html file on the GitHub repository page. Once it is open you will see your HTML. Click the icon in the top right that looks like a pen to begin editing. Change any relative paths in your HTML to the absolute paths for the GitHub repository. So, if your HTML has
       <a href="/otherpage.html"/>
 you need to change it to 
    <a href="https://olddognewtrix123.github.io/otherpage.html"/>

Then of course commit your changes.

Step seven is simple – you wait. Sometimes it can take up to thirty minutes for your changes to show up on GitHub pages. After thirty minutes, plug the name of your repo (<yourusername>.github.io) into your browser. hit Enter, and bask in the glory of your new web page.

Sunday, April 15, 2018

Net Ninja's React JS tutorial in c9.io - skipping webpack by using create-react-app

OK, many are the quirks in c9.io and many many are the quirks in configuring webpacket.

At this point I just want to improve how react itself works and not get bogged down in figgerin out webpacket (I will do that later, however).

So what I did was go through the first page or two of this tutorial: http://www.react.express/environment and am just figuring out how to do the Net Ninja tutorial on top of the template you get when you use create-react-app

The flavors of react are a little different bu I believe that will save me a lot of time.

First I got the create-react-app up and running just fine in the browser.

So going forward I am just tacking the Net Ninja components onto the existing app.

So for example the react app gives you

    import React from 'react';
    import ReactDOM from 'react-dom';
    import './index.css';
    import App from './App';
   import registerServiceWorker from './registerServiceWorker';

     ReactDOM.render(<App />, document.getElementById('root'));
     registerServiceWorker();

and 


    import React, { Component } from 'react';
    import logo from './logo.svg';
    import './App.css';

    class App extends Component {
     render() {
         <header className="App-header">
              <img src={logo} className="App-logo" alt="logo" />
              <h1 className="App-title">Welcome to React</h1>
             </header>
            <p className="App-intro">
              To get started, KLJHKJLHKJ dit <code>src/App.js</code> and save to reload.
             </p>
        );
      }   
    }

    export default App;

So, for the very first component Net Ninja has us build, I just changed App to 

    import React, { Component } from 'react';
    import logo from './logo.svg';
    import './App.css';

    class App extends Component {
     render() {
         return (
          <div className="App">
           <h1>hellooooooooo</h1>
          </div>
        );
      }   

    }

    export default App;


Now, if I wanted to in turn add a child component to App I can just do this:



    import React, { Component } from 'react';
    import logo from './logo.svg';
    import './App.css';
    import Howdy from './Howdy';

    class App extends Component {
     render() {
         return (
          <div className="App">
           <h1>hellooooooooo</h1>
           <Howdy />
          </div>
        );
      }   

    }

    export default App;


and here is the 'Howdy' component:

    import React, { Component } from 'react';
    import logo from './logo.svg';
    import './App.css';

    class Howdy extends Component {
     render() {
         return (
          <div className="App">
           <h1>howdy howdy howdy howdy howdy!</h1>
          </div>
        );
      }   
    }

    export default Howdy;

NOTICE THE FOLLOWING:

The App component can use the Howdy component because the App component contains

     import Howdy from './Howdy';

And the Index component can use the App component because the Index component contains

    import App from './App';

Monday, April 2, 2018

Learning to Code Over 40

I did not get super-serious about learning to code until I myself was in the 40+ set.

Allow me to share with you some hard-won wisdom:

1. DO NOT BE A HELP VAMPIRE

Don't know what a "help vampire" is? Google it. For at least the first year that you are learning this stuff, there are absolutely no questions or conundrums you will encounter that have not already been solved and documented in at least eight places. Unless you are trying to learn some brand spankin' new language or framework that just came out last year, the answers are already there somewhere for you to google. Do NOT add to the pile of stupid, poorly researched questions that have already been answered. You will only serve to discourage those who are willing to provide their time and talent to places like stackoverflow. Ultimately, you are shooting yourself in the foot. Train yourself to dig in and research the crap out of every corner of the internet when you encounter a sticky problem - apparently that is what real developers do. Welcome to the new normal.

2. DO NOT CODE ALONE

OK, obviously you are going to have to code all by yourself to get through the first few dozen tutorials in order to get a baseline understanding (unless you are starting down this road with a coding buddy, which I wish to heck I had!). What I mean, however, is that there is going to be a point where your mind has been expanded by this stuff, and you are champing at the bit to do more than just tutorials. It is a really, really bad idea to continue on all alone at this point. What you are going to end up doing is spend months reinventing the wheel to create nothing but irrelevant, low quality crap. If I sound bitter it is because I myself have wasted several months getting all wrapped up in projects I dreamed up and planned on my own, while all that time and energy could have gone to working with other people and learning the proper things like what good design actually is, what quality code actually is, and how things like Github work. Don't waste your time. Hook up with an opensource project when you are ready to actually start building new stuff.

3. IF IT DIDN'T HAPPEN ON GITHUB, IT DIDN'T HAPPEN

Most likely, the first five questions of any tech interview that you might go to sometime down the road are going to be questions about Github. Github is where your work will be expected to be stored. Github is how the quality of your code will be assessed. If you don't know Github, you don't know squat. If your code is not on Github, nobody is going to bother looking. Again, learn to code as part of a group of remote devs; this will force you to become very github-capable.

Thursday, March 15, 2018

Visual Studio 2012 Coded UI Test for Crystal Reports are too slow - how to speed them up

OK I have been getting really discouraged writing coded UI tests to test the output of Crystal Reports.

Seriously it was taking over seven minutes for one test to run. Ridiculous.

So I took a step back and asked what is the original problem. What do I the human tester actually need and do when manually testing one of these reports?

I decided to set formatting aside. Important, but for my particular needs I could indeed relegate that to other tests or even to manual testing.  The most important thing for me was to test the content of the Crystal report output to make sure what was coming from the database was correct. The other important thing was to run the multiple data exports, which manually involved clicking buttons, waiting, clicking more buttons, dozens of times over.

So the answer so far is to divide, focus, and conquer.

I put the button pushing into entirely separate tests. Now I can just run those UI tests and the machine does all the button pushing for me while I do something that really requires the attention of an actual person.

Back to the content: I just want to make sure the content is correct.

Remember how in your mapWhatever.cs code you've got lines of code that look like

     var something = rpt.UIWEbblahbalh.UIBobjidyaddayadda.somethingsomethingFrame...InnerText

?

That's called threading. Threading is what is going to kill your efficiency with this tool and with theses tests. Threading takes a looong time for some reason. YOU ONLY WANT TO THREAD ONCE IF YOU CAN HELP IT. My problem was I was threading multiple times, slowing my test way down.

So I just figured out how to thread once and get all the content of the report into a single long string (this will vary depending on how your page was built). Then, for the assertion I did StringAssert.Contains(<bigString>, <smallString>)

<bigString> is the big long string of content.

<smallString> is the value I need to make sure appears in the content.

Test takes less than two minutes now. Still slow, but in the acceptable range, because I have to do this same test dozens of time every time we update and have to do general regression testing. Better to have the machine do it.

Tuesday, March 6, 2018

Invalid Host Header Error in a C9 react App

So I am working remotely on a Chingu Voyage remote development project. I need to run and test changes to the application in c9 so I can work on this on my lunch breaks.  To that end, I created a c9 workspace from project's GitHub and tried to run the application we are developing.  I kept getting the invalidHostHeader error message after running npm start.

Tried to google the answer for a couple hours.

Oh my what a headache.

OK, so I FINALLY arrived at what I think is at least a stop-gap solution for my particular situation.

1. Create a file in the root of the application called ".env.development"

2. Update that file to say "DANGEROUSLY_DISABLE_HOST_CHECK=true"

3. Save


BE SURE TO INCLUDE the ".env.development" file in your gitignore file. You DO NOT want this going out with you application. I probably don't even want this on my c9 workstation but it is the only way for me to proceed at the moment.

Saturday, February 24, 2018

Integrating Passport with an Existing Node.JS Application

This is not an exhaustive step-by-step. It is a high level overview of what questions you should be asking yourself as you integrate an authorization service like GitHub's Passport service with an existing node.js application, and roughly in what order you should be asking those questions. Step 0: get an app fully working that you will then be able to open up to other users via some sort of authorization service. So for example I worked through this tutorial and got it working: http://www.clementinejs.com/tutorials/tutorial-beginner.html, then to learn Passport started down this road: http://www.clementinejs.com/tutorials/tutorial-passport.html. Step 1: You then have to register your app with the service ( for this I am registering with GitHub but I think the overall process is roughly the same for any other service like Twitter, Google, or Facebook). The result of your efforts will be an API key that is like the secret door between that service and your app! Step 2: Back in your application, set up the data model to use the information that will come in from the API. The fields you add will typically be something like id, displayName, userName, and publicRepos (notice there is no need to store passwords or any of the associated headaches; that is one big reason for using one of these authorization services) Step 3: In you application, make sure the API key and any related stuff from the authorization service gets stored in your .env file and then that .env file gets included in the stuff that does NOT get pushed up to GitHub (if you are indeed using GitHub as your code version management repository - sorry, this is an assumption on my part) Step 4: Authorization Configuration. Huh-boy, here we go. The thing is, the authorization service we are using (gitHub in this case) needs to be able to confirm your application has permission to access the authorization service's API and retrieve user information. To that end, your application needs to reference the Node process.env object. So you have to export it so it is available (via require) in other parts of your application. Step 5: Set up the authentication part of your application. Step 6: Changing your existing application means adding lots of new functionality and changing a lot of existing functionality. This varies from application to application and authorization service to authorization service. What follows are examples of the kinds of questions you have to ask yourself before you can get your application to play ball with the authorization service you chose to work with. - Make sure that, in the transition from your original application to a version that uses Passport, you made any modifications to your server-side code that accounts for these changes ( for example, did changes to which model you are using require updates to the server-side controller?) - Do not forget to also change and update routes accordingly (for example, make sure passport is one of the arguments for the main function in routes - this will expose the stuff that comes with Passport to your routes)! - Now that the application is using an authentication service, the user needs to have a loggedin/notloggedin state; typically this is handled by a function in routes. - Similarly, did you update your AJAX functionality? Step 7: Changing your existing application to use an authorization service will mean adding new views and updating others Step 8: Changing your existing application to use an authorization service will mean some of the views that you add to your application will need additional controllers to work with the API connecting your application to the data the authorization service provides. Most likely you will need an additional controller that updates the view(s) with information it retrieves the user information from the API.