Injecting Custom Files into Ionic Build

This post is about including custom .html, .css and .js files in an Ionic 3.x+ project so that they get copied from /src to /www during the build process. Basically, we are talking about files that are handled separately from the webpack compiler process, but you want them to be swept into the test or production build when they get updated.

Step 1: Modify your projects main package.json file in the root directory to override the copying process in ionic:build and ionic:serve. In this example we are referencing a custom library called ionic-config-override.js that controls what we want to copy, and this library lives in the root directory, as well.

{
     . . .
     “scripts”: {
          . . .
          "ionic:build": "ionic-app-scripts build --copy ionic-config-override.js",
          “ionic:serve”: "ionic-app-scripts serve --copy ionic-config-override.js"
     }
     . . .
}

Step 2: Create a JavaScript file of the same name you referenced in package.json for example ionic-config-override.js. In this new JavaScript library use the node.js fs-extra file utility to copy the files you want when the build process is run. Here’s one example:

var fs = require(‘fs-extra’);
fs.copy(‘src/special.html’,’www/special.html’);

Step 3: To test locally instead of using ionic serve, run this new script using the command line command npm run ionic:serve. Or, if you are ready to test on a device run the script using npm run ionic:build android and then when that is completed successfully use ionic cordova run android.

References:
Ionic –copy command

The Copy command source code can be found in your project path @ionic/app-scripts/config/copy.config.js

Additional information can be found on the Ionic forums.

Tips for loading jQuery in mobile apps

Whether you are using jQuery by itself or with Bootstrap there are a few things to remember if you don’t want to see the following error: “Uncaught ReferenceError: $ is not defined”.  This error happens because you are trying to access jQuery before the library has finished loading. There are several ways to fix the error.

Encapsulate jQuery functionality inside a function. This keeps the parser from attempting to execute any jQuery until the function is explicitly called and it allows us to place the script tag at the bottom of the app. This approach can get tricky if jQuery is slow to load. It’s possible that the button can be visible and clickable before jQuery has finished loading. If this happens your app will throw an error. You can try it out in jsfiddle here.


<!DOCTYPE html>
<head lang="en">
    <title>jQuery Test</title>
</head>
<body>

<button id="button1">Click me</button>
<div id="div1" style="background:blue;height:100px;width:100px;position:absolute;"></div>
<script>

    // Test if jQuery is available
    if(typeof jQuery !== 'undefined'){
        console.log("jQuery has been loaded");
    }
    else{
        console.log("jQuery has not been loaded");
    }

    document.getElementById("button1").onclick = function(){
        $( "#div1" ).animate({
            left: "250px",
            height:'150px',
            width:'150px'
        });
    };

</script>
<!-- Everything above this will load first! -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js" ></script>
</body>
</html>

Use the script tag onload event to initialize jQuery functionality. This follows the guidelines of the first suggestion above and then waits to fire off any functionality until after the jQuery library has completed loading. This insures jQuery is loaded before it can be used. You can try it out in jsfiddle here.

<!DOCTYPE html>
<head lang="en">
    <title>jQuery Test</title>
</head>
<body>
<div id="div1" style="background:blue;height:100px;width:100px;position:absolute;"></div>
<script>

    // Test if jQuery is available
    if(typeof jQuery !== 'undefined'){
        console.log("jQuery has been loaded");
    }
    else{
        console.log("jQuery has not been loaded");
    }

    // Run this function as soon as jQuery loads
    function ready(){
        $( "#div1" ).animate({
            left: "250px",
            height:'150px',
            width:'150px'
        });
    }

</script>
<!-- Everything above this will load first! -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js" onload="ready()" ></script>
</body>
</html>

Place script tag in head. Sometimes lifecycle issues in mobile web apps will require us to simply load jQuery from the head of the web app. Because this forces jQuery to load synchronously before any user interface elements we pretty much guarantee that jQuery will be available when we run JavaScript within the body of the application. Try it out in jsfiddle here.


<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>jQuery Test</title>
    <!-- Block DOM loading until jQuery is loaded -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
</head>
<body>
    <button id="button1">Click me</button>
    <script>

        // Test if jQuery is available
        if(typeof jQuery !== 'undefined'){
            console.log("jQuery has been loaded");
        }
        else{
            console.log("jQuery has not been loaded");
        }

        // Page is fully loaded including any graphics
        $(window).load(function() {
            console.log("window.load worked!");
        });

        // According to jQuery docs this is equivalent
        // to the generic anonymous function below
        $(document).ready(function() {
            console.log("document.ready worked!");
        });

        // The DOM has been loaded and can be accessed
        $(function() {
            console.log("DOM loaded worked!");
        });

        $( "#button1" ).click(function() {
            alert( "Handler for .click() called." );
        });

    </script>
</body>
</html>

Going Offline with HTML5 and JavaScript, Part 1

There are two primary use cases for going offline with mobile HTML5 web applications and JavaScript: partial offline and full offline. Before diving into building offline apps, understanding the differences between these use cases will help you build the best applications for your requirements. The functionality in modern browsers has finally gotten to the point where it is feasible (and fun!) to build offline web applications.

Partial Offline. Partial offline means the vast majority of the time the application is online, however it can continue to work if the internet connection gets temporarily interrupted. A partially offline app understands that requests for remote resources, that is resources that don’t exist on the device, will automatically defer to local resource, or at least fail gracefully, during the period of time when an internet connection doesn’t exist. Partially offline apps typically cannot be reloaded or restarted offline. The coding required to handle this scenario is much lighter weight than the architecture required for going fully offline. An example of partial offline is a reader app that pre-caches certain HTML pages of your choice. If the internet connection gets disrupted you can continue reading and navigating between the cached pages.

The partially offline scenario exists because there is no such thing as a perfect internet connection for mobile. In reality, internet connections and download speeds are very choppy when measured over a period of minutes or hours. Sure, some internet providers market 4G connections as being extremely fast, or have the best coverage etc., etc., blah. The bottom line is cellular and even WiFi internet connections are not guaranteed. A good example of this is coffee shops. They don’t come with an uptime guarantee, so if a couple of yahoos sitting next to you are streaming HD Netflix then that will surely bring the internet connection to its knees.

In reality, if you don’t live danger close to a cell phone tower and are moving around doing your job or running errands chances are your internet connection will fluctuate up and down over time. Anyone that owns a smartphone has experienced this at one time or another. Dropped calls are perfect example. You may be shopping and going in and out of buildings, or hanging out in the back of a taxi, sitting in your car pulled off the side of the road, or perhaps even just watching your kids as they play in the neighborhood park. A web application architected for partially offline will let you keep surfing or working for a short period of time, and hopefully long enough until the internet connection comes back up.

Full Offline. A fully offline JavaScript application is one that starts out online to download all the necessary data and files, then it can be completely disconnected from the internet. These apps can survive browser restarts and reloads, they can stay offline indefinitely and/or they can be resynced online at some point in the future.

Fully offline apps need to be architected in a much more robust way than their partially offline cousins. Partial offline apps can be considered more fragile than fully offline apps because they can’t be restarted or reloaded while offline, and you have to be very careful to limit their capabilities while offline otherwise the user can easily break the app. Fully offline apps are built with the knowledge that they may be offline for extended periods of time and need to be self-sufficient because users will be depending on them. If a fully offline app breaks then the user will be completely hosed (and very unhappy) until some point in the future where the internet connection can be restored and they can resync the app.

Offline apps can break in any number of interesting ways such as throwing a 404 when the user hits the back button or simply crashing when the app unsuccessfully attempts to a load a new page. By their very nature, fully offline apps may have larger and more complex data storage and life cycle requirements. They cache entire HTML web pages and all their associated JavaScript libraries, images and supporting data.

Examples of full offline apps include mapping apps, web email, reader apps, and any other apps that require information from a database.  User data is typically downloaded locally, stored on disk and then accessed by offline web applications. Any data that’s stored in memory will be lost when if the device or browser is restarted while offline.

 

Web offline versus Native offline

When building out your requirements, it’s a best practice to do an honest comparison between offline web capabilities and the offline capabilities of native SDKs.  In general as of the writing of this post, it’s fair to say that native apps still offer much more robust offline capabilities than the latest versions of mobile browsers. There are a few exceptions where browsers may have similar capabilities but almost always the level of control is more limited.

Native apps have the advantage because they basically have direct access to the device operating system and many of the capabilities are simply integrated into the respective SDKs. Here is a partial list of capabilities that are commonly seen in native offline requirements:

Web apps, on the other hand, run within the browser and are subject to any limitations imposed by the browser. The browser, itself, is a native app and it restricts it’s own children (web apps) to certain security restrictions. A few examples of web app limitations include:

  • Access to a limited number of censors. Access is not consistent across different browser types.
  • Limited control over location services via HTML5 Geolocation API.
  • JavaScript cannot programmatically read and write non-cached files on the device without user intervention.
  • Internet connectivity detection typically dependent on 3rd party libraries such as offline.js. Support is inconsistent across some platform/browser combinations.
  • Indirect and limited control over battery life and optimization.
  • Browsers and any of their associated tabs stop running as soon as the browser is minimized. If you have a requirement for the app to “wake up” from a minimized state under certain conditions you will have to go native.

 

Summary

Partial offline applications are design to continue working gracefully during intermittent interruptions in connectivity. Because offline is considered a temporary or even momentary condition in this use case, partial offline apps can use lighter weight architecture and have smaller data storage needs than full offline apps.

Fully offline apps are designed to be taken offline for extensive periods of time. They have to meet more demanding requirements and need a comprehensive architecture that enables storing of HTML files, JavaScript libraries, and user data as well as being able to handle browser reloads and restarts while offline.

Lastly, when having conversations about building offline apps you should weight web versus native offline capabilities against your requirements. Native SDKs still offer much richer control over most of the aspects of offline functionality.

Stay tuned for additional posts on this subject. Part 2 will look at the features and APIs you can use to take applications offline.

 

References

10 ways to deal with intermittent internet connections

How accurate is Android GPS? Part 1: Understanding Location Data

Wikipedia – Browser Security