App shell model


The App Shell Model

Our app looks great, but there is always room for improvement. If we want to compete with native apps, we have to work on our app load time.

If you test your website on a fast internet connection, you may have not noticed the blank screen - but it is there, even more so when user with a lousy signal downloads our monolithic JavaScript file.

Throttling settings
You can emulate slow network connections from the Network Throttling menu in the Chrome browser dev tools or Firefox's.

It's because of how modern single page apps work - at the first load, we serve the index.html file, which for now is just a blank page with div#app. Next, the JS bundle is downloaded and then it has to boot up our Vue application. This approach lets us make our website dynamic, immersive and interactive, but the downside is that it significantly increases load time.

As developers, it is our duty to consider every user, who may live in the areas where the network speed is not so impressive. We want to ensure that all users have the best possible experience.

In today's lesson, I want to introduce you to the concept of the App Shell.

The App Shell

The Application Shell architecture is a concept of separating the content of your app from the UI shared across different views. In other words - the app shell is a part of the app which does not change often. We want the minimum HTML and CSS to display something meaningful to the user as soon as possible. The first load should be extremely quick and then get immediately cashed. The JS bundle is always too big, as well - let's reduce it.

1. Let's remove our stylesheets import in the src/main.js file and replace them with link tags in the root folder's index.html's head tag. We are doing it so that the critical resources can be fetched quick, along the initial markup and without waiting for our heavy-weight JS.


        <!-- Bootstrap core CSS -->
        <link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.2.1/css/bootstrap.min.css"
          rel="stylesheet">
        <!-- Material Design Bootstrap -->
        <link href="https://cdnjs.cloudflare.com/ajax/libs/mdbootstrap/4.7.1/css/mdb.min.css" rel="stylesheet">
      

Note!

Since we will be linking to the stylesheets directly in our index.html, there is no need for mentioning bootstrap's CSS for the second time, as a dependency in our package.json. Feel free to delete it from there. Remember to yarn the project if you do.

2. Using browser dev tools, copy the HTML code of our app. Paste it inside div#app in the root directory's index.html.

Copy HTML

The markup copied that way will have Vue-specific hash-named attributes starting with data-v-{hash}. Their purpose has to do internal workings of the framework - they are used to seamlessly identify DOM elements. You don't have to worry about them being there, feel free to keep them or delete. The easiest way is to find all places a particular attribute appears is either by using a search tool or, in newer versions of VSCode, by selecting one and keep on pressing Ctrl + D to select the others, then Del / Backspace. To skip this manual labour have a look below, where a markup that has already been tidied up is presented.

See the class-less, id-less div beneath the Today: header? These are our events - live, dynamic, fetched from a server, cache or localStorage. Right now we are working on the static HTML, one to be displayed before anything else happens - it has no idea about events to display, as it did not have a chance to ask the backend about them yet. This is why, instead of pretending we know stuff we really don't, let's give our users an indication of progress during the initial app load. Delete these pesky events' markup in their class-less, id-less tags and paste the code for a Bootstrap loader instead.


        <div class="d-flex justify-content-center">
          <div class="spinner-border" style="width: 3rem; height: 3rem;" role="status">
            <span class="sr-only">Loading...</span>
          </div>
        </div>
      

Way better. Now refresh the page - for a brief moment, you should see our app with a loader. When the JavaScript finishes downloading and the initialisation process kicks in, Vue will generate content to replace whatever is happening in the div#app element.

Right, now a complete ./index.html code should look something like this:


        <!DOCTYPE html>
        <html>

        <head>
          <meta charset="utf-8">
          <meta name="viewport" content="width=device-width,initial-scale=1.0">
          <title>mdbvue</title>
          <script src="https://maps.googleapis.com/maps/api/js" async></script>
          <link rel="manifest" href="/static/manifest.json" />
          <!-- Bootstrap core CSS -->
          <link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.2.1/css/bootstrap.min.css"
            rel="stylesheet">
          <!-- Material Design Bootstrap -->
          <link href="https://cdnjs.cloudflare.com/ajax/libs/mdbootstrap/4.7.1/css/mdb.min.css" rel="stylesheet">
        </head>

        <body>
          <div id="app">
            <div class="container">
              <div class="row">
                <div class="col-9">
                  <h2 class="text-uppercase my-3">Today:</h2>
                  <div class="d-flex justify-content-center">
                    <div class="spinner-border" style="width: 3rem; height: 3rem;" role="status">
                      <span class="sr-only">Loading...</span>
                    </div>
                  </div>
                </div>
                <div class="col-3">
                  <h3 class="text-uppercase my-3">Schedule</h3>
                  <h6 class="my-3">
                    It's going to be busy that today. You have <b>4 events</b> today.
                  </h6>
                  <h1 class="my-3">
                    <div class="row">
                      <div class="text-center col-3"><i class="far fa-sun"></i></div>
                      <div class="col-9">Sunny</div>
                    </div>
                    <div class="row">
                      <div class="text-center col-3"><i class="fas fa-thermometer-three-quarters"></i></div>
                      <div class="col-9">23°C</div>
                    </div>
                  </h1>
                  <p>
                    Don't forget your sunglasses. Today will dry and sunny, becoming warm in the afternoon with
                    temperatures of between 20 and 25 degrees.
                  </p>
                </div>
              </div>
            </div>
          </div>
          <!-- built files will be auto injected -->
        </body>

        </html>
      

And this is how we let our users know stuff is happening in the background! Deploy this new, sweet feature using yarn deploy.

Something doesn't work for you? Check the code for this lesson on our repository


Previous lesson Download Live preview Next lesson

Spread the word:
Do you need help? Use our support forum

About the author