DEV Community

K
K

Posted on

Easy Offline First Apps With Webpack's Offline Plugin

TL;DR Here is a repository with a working example. :)

Many of your have probably noticed all the buzz about offline first Web-apps. The Web is full of articles about the AppCache about Service Workers and such and now you ask yourself, how do I can get my apps work offline, like the cool kids. Or you simply asked, how come that data I already have on my device isn't shown to me anymore?!

Well, there are a bunch of technologies to help you with this, but this seems a rather fast paced topic these days. So first things first.

If you write a single page application, you often have different types of request your app sends. Some get images, some get styles, some code and some actual user data.

Caching User Data

For the last point, the user data, you will basically store the whole stuff somewhere on the client. Since this depends mostly on your business logic, it is advisable to write at least part of that logic yourself.

You can use localStorage for this if a key-value-store is enough or, indexed DB if you need a more sophisticated datastore. There are even libraries that help with the usage of these low-level Web-APIs. Like PouchDB and LocalForage.

Caching Assets

But this post is about your assets. Your HTML, CSS, JS and Images.

If you bundle your assets with Webpack, there is a really easy way: The offline-plugin.

After building with this plugin, you can call a function, that will make all Webpack generated assets available offline.

A basic webpack.config.js could look like this:

const HtmlWebpackPlugin = require('html-webpack-plugin')
const OfflinePlugin = require('offline-plugin')

const html = new HtmlWebpackPlugin({template: './src/index.html'})
const offline = new OfflinePlugin

module.exports = {
  entry: './src/index.js',
  output: {
    filename: '[name].[hash].js',
    path: './assets/',
  },
  plugins: [html, offline],
}
Enter fullscreen mode Exit fullscreen mode

Pitfall: Non-Webpack Assets

Now you probably ask, why does the basic version need another plugin? Well, the offline-plugin has a catch.

It will only cache the assets that are produced by Webpack if it isn't handed any configuration object.

So if you have an index.html, which you don't generate with Webpack, it won't be cached and your whole app won't show when there is no connection.

Using the html-plugin is a way to get around this problem. Then the index.htmlwill be included.

Another way is using externals:

const offline = new OfflinePlugin({
  externals: ['index.html'],
})
Enter fullscreen mode Exit fullscreen mode

This is also used for assets from another server, for example if you require Bootstrap or jQuery from a content delivery network (CDN.

I found it a bit confusing at first, because I thought of externals as API requests and CDN assets. But it basically means: files not built by Webpack

The basic config won't give you any warning, only if you try to manually configure the caches you will maybe see this:

WARNING in OfflinePlugin: Cache asset [index.html] is not found in the output assets,if it's an external asset, put it to the |externals| option to remove this warning

Pitfall: Cached Forever

The basic approach is to require the offline-plugin runtime at the beginning at your code and install it. Which basically means enable caching.

const offlinePluginRuntime = require('offline-plugin/runtime')
offlinePluginRuntime.install()
Enter fullscreen mode Exit fullscreen mode

But you don't have to activate the caching automatically on application start. This can lead to unexpected behaviour if you're not used to offline modes.

For example, you could upload another version of a file and give it the same name, so it won't change on the client.

Or you have an API call in externals and now only the cached results are shown.

This can greatly help with debugging.

Conclusion

The offline-plugin is a really easy way to show already downloaded data to your users, even if they aren't online. These days, where more and more people are online via mobile devices, this offline scenario becomes less and less of an exeption.

Latest comments (3)

Collapse
 
bernarda profile image
BernardA

I came here directed by folks from react-loadable, react-loadable-visibility.
The intent was to use your plugin in conjunction with the former.
The issue is that react-loadable and visibility are not fetching files from cache, but from the network. Any ideas from your perspective on why?
I was previously using workbox-webpack-plugin with the same result.

Collapse
 
kayis profile image
K

I didn't make this plugin, this guy did.

I just wrote a small tutorial about it.

And sorry, I don't know why it doesn't fetch from the cache, didn't use it for over a year.

Collapse
 
hackingbeauty_1 profile image
Mark M. Muskardin

Thank you for writing this.