Author: Mikołaj Smoleński
Free live lesson
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.
It's because of how modern single page apps work - at the first load, we serve the
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">
Since we will be
linkingto 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
yarnthe project if you do.
2. Using browser dev tools, copy the HTML code of our app. Paste it inside
div#app in the root
The markup copied that way will have Vue-specific hash-named attributes starting with
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>
finishes downloading and the initialisation process kicks in, Vue will generate content to replace whatever is
happening in the
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
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: