Nuxtjs + Prismic + OneSignal = Awesome PWA

Nuxtjs + Prismic + OneSignal = Awesome PWA

Introduction

Progressive Web Apps (PWA) combine the capabilities of native apps with the reach of web apps. They are powered by modern APIs to deliver reliability and reach to anyone, on any device, with the a single codebase. Though they’ve been around since the early 2000s with the creation of XHMLHTTPRequest, the term was first coined by Google in 2015. See The history of PWA development . Since then modern web frameworks have come along to make developing them much easier.

Building a Progressive Web App

This guide will walk through building a blog site that gets it’s content from prismic.io and sends a push notification to subscribed users via onesignal whenever new content is published.

Lets start by installing nuxt and the dependencies we’ll need for this to work. To keep this guide short I won’t be touching the nuxt installation process. If you’ve never used it before please take a look at their getting started guide .

After installation, run the following command to install the packages we’ll need.

npm i @nuxtjs/onesignal @nuxtjs/prismic @nuxtjs/pwa express request prismic-dom prismic-javascript @nuxtjs/moment

Enable prismic, onesignal and nuxt’s pwa module by adding them to the modules array of the nuxt.config.js file.

...
modules: [
   '@nuxtjs/prismic',
   '@nuxtjs/onesignal',
   '@nuxtjs/pwa',
   '@nuxtjs/moment'
]
...

PS: installing the nuxtjs/pwa module converted your application in a pwa — so yay! No need to manually setup service workers :)

To override the default settings (recommended) you can add the following to your config file.

...
pwa: {
  manifest : {
      name: 'Nuxt Blog',
      short_name: 'Nuxt Blog',
      description: 'This is an awesome medium article', 
      icons: [
       {src: '/icon.png', sizes: '512x512', type: 'image/png'},
       {src: '/icon.png', sizes: '512x512', type: 'image/png', purpose: 'any maskable'}
      ]
    }
}
...

Maskable icons ensures your PWA icon looks great on all Android devices and is a requirement to pass the lighthouse PWA audit. Read more about that here.

Configuring prismic

Now it’s getting good!

Prismic is an API-based headless CMS that’s fairly easy to use. It’s API is based off of graphql so if you’re familiar using it will be snappy. For developers, like myself, who never used graphql don’t worry there’s no need to use it to fetch content. Let’s dive in:

  • Create a prismic account and login
  • Create a repository
  • Create a repeatable custom type (Blog posts) and setup the fields that you’ll later use to add content.

1_KsjbEWbRhL3GVY9Bl64IwQ.png

1_JM77p6rL0bKUAVOXxvQ4AA.png

1_cNuZrntYfcqZcpJMfgwWbQ.png

Think of this as creating a custom WYSIWYG editor, which in essence is exactly what it is. To mimic what I have here paste this into the JSON editor.

{
  "Main" : {
    "featured_image" : {
      "type" : "Image",
      "config" : {
        "constraint" : {
          "width" : null,
          "height" : 302
        },
        "thumbnails" : [ ],
        "label" : "Featured Image"
      }
    },
    "post_title" : {
      "type" : "StructuredText",
      "config" : {
        "single" : "heading1",
        "label" : "Post title",
        "placeholder" : "Post Title"
      }
    },
    "uid" : {
      "type" : "UID",
      "config" : {
        "label" : "slug"
      }
    },
    "post_content" : {
      "type" : "StructuredText",
      "config" : {
        "multi" : "paragraph, preformatted, heading1, heading2, heading3, heading4, heading5, heading6, strong, em, hyperlink, image, embed, list-item, o-list-item, o-list-item",
        "allowTargetBlank" : true,
        "label" : "Post Content",
        "placeholder" : "Start typing here..."
      }
    }
  }
}

This mimics the typical fields you’ll find in the WordPress editor, though the layout is different.

  • Setup the link resolver — necessary for returning the appropriate paths from the rich text and link fields in your prismic repo. It will take a document object as an argument and return the corresponding route of your website.

In the plugins directory create link-resolver.js and add the following content.

export default function (doc) {
    if (doc.isBroken) {
      return '/not-found';
    }

    if (doc.type === 'blog') {
      return '/blog/' + doc.uid;
    }

    return '/not-found';
 };

Lastly, we’ll update our config file to include the link resolver and serializer like so:

...
prismic: {
    endpoint: 'https://{project-name}.cdn.prismic.io/api/v2',
    linkResolver: '@/plugins/link-resolver',
    htmlSerializer: '@/plugins/html-serializer'
},
...

Endpoint can be found by going to settings->API & Security.

Connecting to the API

Lets now make a blog component and fetch some data from the API.

First things first — create some content in prismic. Log into your dashboard and create a new document.

1_Ya8f8aUKSVfEVE703sQ89g.png

Take note of the fields that we created earlier. Add some content and click publish. It will show up in the dashboard like this.

1_P5Q_1jpK1NKx4eCqZmK5Iw.png

In your pages directory create a sub-directory called blog with an index.vue file. Also inside of blog create a folder a called _id with another index.vue file. Your directory structure should now look like this:

...
pages
|--blog
|---index.vue
|---_id
|----index.vue
...

In blog->index.vue we’ll be getting and display a list of all the documents published on prismic.

1_cETsKkpvNJYON210Ds5Kkg.png

Remember when we installed the nuxtjs/prismic module at the very start? Well this allows us to call $prismic from any part of our application and we’re simply running an asynchronous function to fetch the data.

const query = await this.$prismic.api.query(this.$prismic.predicates.at('document.type', 'blog_posts'),{orderings: '[document.first_publication_date desc]', pageSize: 9}).then((query)=>{
this.docs = query.results;
})

The above gets all documents of the type blog_posts sorted by the date first published in descending order, limits the page size to 9 and stores the results in the docs array.

Push Notifications with OneSignal

We’ve already installed the required nuxtjs/onesignal module and added it to our config file. What’s left to do:

  • Create a one signal account and add an app.

1_GeLiidmT73Amw3mQ_KPI8g.png

Name your app, select Web Push and click Next.

For testing purposes these are the only fields you’ll be editing. Click save and let’s head back to our project directory. DO NOT download the SDK files or paste the code provided into anywhere, the nuxt/onesignal module does this for us.

See OneSignal’s official documentation for setting up on localhost if you have any problems.

1_mQGBwOfpQV963h_9rApc7w.png

In your config file paste the following to initialize onesignal:

...
oneSignal: {
   init: {
   appId: 'xxx-xxxx-xxx-xxxx',
   allowLocalhostAsSecureOrigin: true,
   welcomeNotification: {
     disable: false
   }
 }
}
...

Your app id is visible in the browser when you navigate to the project dashboard or by going to Settings->Keys & IDs.

IMPORTANT: To send push notifications to users of all segments onesignal requires you to send the API key as Authorization: Basic along with Content-Type: application/json in the request header.

Configuring the webhook listener

We’ll be creating this using express. Start by creating a directory called server in your project root and a file therein called index.js.

Add the code found here replacing all necessary variables with your own:

Start the express server by going to and running node index.js

Since we’re on localhost we need to expose it to the web in order to test the webhook. For that, install ngrok then run ./ngrok http 5000 to expose the express server to the internet.

Copy the https version of the link and in Prismic navigate to Settings->Webhooks and click Create a webhook.

Paste the ngrok url and append the route from the server index.js file.

https://{some-random-hash}.ngrok.io/notifications
`

Uncheck all triggers except “A document is published” and click Add this webhook.

1_Q3XClRvd-ODYDYpoENfL0A.png

Substitute the onesignal’s notification api url in the post method of index.js with a public requestbin url (private bins don’t work) to test the data being sent.

Did you find this article valuable?

Support Kalpa Services Inc. by becoming a sponsor. Any amount is appreciated!