Building Offline-First Apps With Node.js and SQLite
Let's learn about progressive web apps - applications that can use web-platform features and progressive enhancement to provide users with an experience comparable to native apps.
Join the DZone community and get the full member experience.
Join For FreeThis tutorial will teach you how to build an offline-first application with Node.js and a SQLite database. Let's start with an introduction to progressive web apps.
Introduction to PWA
Progressive Web Apps (PWAs) are web apps that use service workers, manifests, and other web-platform features and progressive enhancement to provide users with an experience comparable to native apps.
PWAs can sometimes outperform native apps in terms of efficiency. They operate on demand and are always available without consuming valuable smartphone memory or data. Users consume less data when choosing a PWA over a native version of the same application. They can still save the PWA to their home screen; it's installable without the need for a full download.
What Are We Building?
To demonstrate the power of progressive web applications, we'll be building a simple blog application.
The user will be able to interact with it like other PWAs, such as the Twitter PWA. Let's get right to it.
Initialize NodeJs Application
Let's get our hands dirty. To get started, we'll create our project folder with the command below:
mkdir PWA && cd PWA
Then, we'll initialize a Node.js application with the commands below:
npm init -y
The above command creates a package.json
file for the application.
Next, create the following folder structure in our project folder:
Set Up an Express Server
With our application setup, let's install Express to create our Node.js server with the command below:
Then, we'll create a couple of folders and files in the public folder:
- css/style.css file
- js/app.js file
Next, create an index.js
file in the project root directory with the following code snippets below:
In the code snippet, we import express to create our server and the path module. We configured our app to render our static files using the express.static method, which takes the path to the static folder (public), we created the root route of our application and rendered the index.html file. Then we configured the app to listen to port 8000.
Connect to SQLite Database
With the server setup for our application, let's create and connect our application to save our blog details. To get started, run the command below to install the sqlite3 dependency.
Then, in the entry point index.js
file, add the code snippet below to create and connect the application to an SQLite Database.
Next, we'll create a list of blogs which we'll store in our database and render later to the client-side with the code snippet below:
Each block post in our application will have an id, title, avatar, and intro fields.
Now create a database table name blogs and save the blog details we just created above with the code snippet below:
In the code snippet, we created a table blogs using the db.run. The db.run method takes an SQL query as a parameter, then we loop through our array of blogs and insert them into the blogs table we just created using the js map function.
View Database Records
Now let’s view the records we just created using Arctype. To view the records in your SQLite database using Arctype, follow the steps below:
- Install Arctype
- Run the Application with
node index.js
to create a database - Launch Arctype and click on the SQLite tab
- Click on the Select SQLite file button, and locate the db.sqlite file generated when you ran the server.
- You should see the blogs table and the records we create as shown in the screenshot below:
Render the Page
At this point, we have connected the application to an SQLite database and also inserted some records in the database. Now, open the index.html file and add the following code snippets below:
We created a simple markup with links to our manifest in the above file, which we'll be creating in the next section, styles, and app.js files.
Then, we'll create a blogs route in our index.js file to return the blogs to the client-side.
In our public/js/app.js file, we'll send a get request to the blog endpoint to get the blogs from our backend. Then we loop through the blogs, target the container class and display them.
We'll also add some styling to our application in the public/css/style.css with the code snippet below:
Now open the package.json file and add the start script.
At this point, we've set up our application. But we cannot run our application when the server is not running or when there is no network connection for production. Let's set that up in the next section.
Optimizing Application
We need to make our application compatible with all screen sizes. We'll also add a theme color by adding the markup below in the head section of our index.html file.
Create a Manifest
We need to describe our app and how it should behave when installed on the user's device. We can do this by creating a manifest.
Create a manifest file in the project root directory and add the following configurations:
In our manifest, we defined the following configurations:
- name: This defines the app's display name.
- short_name: This defines the name that will be displayed under the app icon when installed.
- start_url: This tells the browser the root URL of the application.
- display: This tells the browser how to display the app.
- background_color: This defines the background color of the application when installed.
- theme_color: This defines the color of the status bar.
- orientation: This defines the orientation to use during the app display.
- icons: This defines the icons or images of different sizes to be used as our app home icons.
Creating our home screen icons manually can be a very complicated task, but not to worry. We'll take advantage of a third-party module known as pwa-asset-generator to generate icons of different sizes from our main app icon inside the public directory with the command below:
The above command will create an icons folder inside the public folder with many icons for our application, along with some JSON on the terminal that we will paste into our icons array in the manifest.
The icons array in our manifest should look like this:
Also, the command generated the markup links to the icons generated.
Copy and paste the markup to the head section of the markup in the public/index.html file.
Setup Service Workers
With our manifest created, let's set up the service workers. A service worker is a piece of JavaScript code that your browser runs in the background in a separate thread to handle the cache for assets and data that you save for future requests to enable offline support for your application.
So create a blogger.serviceWorker.js file in the public folder. For the service worker, there are many events (push, activate, install, fetch, message, sync), but for the demonstration in this tutorial, we'll cover the install, activate, and fetch events. Before that, we need to create an array to store all the assets we used in our application.
Then, we'll listen to the install event to register and save our static files to the browser's cache. This process takes some time to complete. To skip the wait, we'll use skipWaiting().
Then, we need to clear the cache to remove the old assets whenever the service worker is updated. For that, we'll listen to the activate code snippet below:
In the above code snippet, we use the waitUntil method on the service worker. This method waits for the action to finish, and then we check if the assets we are trying to clear are the assets of our current app before we delete them.
Next, we need the files stored in our cache to use them.
When a request is made on the page, PWA will check our cache and read from it if there is data in the cache rather than going to the network. Then, using the respondWith method, we override the browser's default and make our event return a promise. When the cache is complete, we can return the cache corresponding to the evt.request. When the cache is ready, we can return the cache that matches the evt.request.
We have successfully set up our service worker. Now let's make it available in our application.
Register the Service Worker
Now let's register our service worker in our public/js/app.js file with the code snippet below:
Here, we check if our application's browser supports service workers (of course, not all browsers support service workers), then register our service worker file.
Now run the application with the command below:
Go to localhost:8000 in your browser to access the app.
Google Lighthouse Check
Now let's check if we properly set up our PWA using a Google Lighthouse check. Right-click on your browser and select "inspect." On the inspect tabs, select lighthouse and click on generate report. If everything went well with your application, you should see an output like the one in the screenshot below:
We have successfully created our first application. You can also stop the server to test the application in offline mode.
Conclusion
Progressive Web Apps (PWA) use modern APIs to provide enhanced capabilities, dependability, and installability with a single codebase. They allow your end-user to use your application regardless of whether or not they have an internet connection. You should feel free to fork the repository and add additional features to the project. Good luck!
Opinions expressed by DZone contributors are their own.
Comments