/vue-qewd

Primary LanguageJavaScript

vue-qewd: Vue.js & Nuxt.js WebSocket client plugin for QEWD.js

This plugin integrates Vue.js & Nuxt.js applications with a multi-process qewd (QEWD.js) Express or Koa back-end server using WebSockets (or Ajax calls). Exposes the ewd-client module as a this.$qewd built-in Vue.js service inside your Vue.js components.

A similar react-qewd module exists for React/Redux.

QEWD.js is a unique web framework allowing you to concentrate on your application code, without worrying about system infrastructure, featuring:

  • a WebSockets server, allowing your application to connect via this vue-qewd module using ewd-client
  • a (federating) REST server, to build your REST endpoints & allowing you to federate requests to other (chained) QEWD servers, featuring Express or Koa as underlying frameworks
  • a microservices server, using very efficient (permanent, secured) WebSocket connections to other QEWD.js servers using JWT's
  • a GraphQL server to write & process your GraphQL queries & mutations
  • an application router to orchestrate all your different application endpoint(s)/handler(s)
  • a master/worker multi-process queue architecture, high-performance and very scalable
  • session management/cache allowing you to write stateful applications
  • response customization: combine responses from different servers, return responses in different formats, intercept an re-route requests, ...
  • built-in JSON database abstraction: make your application data persistent using the InterSystems CachĂ© multi-model database or the InterSystems IRIS Data platform (unified data access as a document/NoSQL store or using SQL or objects), Redis, YottaDB, ...

Installing

npm install vue-qewd

Version 2: breaking changes!

From version 2.0.0 onwards, the socket.io-client and jQuery module dependencies for the underlying ewd-client need to be passed in as parameters when instantiating QEWD:

import io from 'socket.io-client'
import $ from 'jquery'

let qewd = QEWD({
  application: 'qewd-test-app', // application name
  log: true,
  url: 'http://localhost:8080',
  io,
  $
})

Overview of parameter changes in 2.0.0 and up:

  • io was added: required for WebSocket communication mode, import it as above or as
var io = require('socket.io-client')
  • $ was added: required for Ajax communication mode using the jQuery ajax method, import it as above or as
var $ = require('jquery')
  • ajax remains the same: required for Ajax communication mode, using you own custom Ajax module, e.g. with axios
import io from 'socket.io-client'
// import $ from 'jquery'
import axios from 'axios'

var qewd = QEWD({
  application: 'qewd-test-app', // application name
  log: true,
  url: 'http://localhost:8080',
  io,
  ajax: function (params, success, fail) {
    let data = JSON.stringify(params.data)
    axios({
      url: params.url,
      method: 'post',
      headers: {
        'Content-Type': params.contentType
      },
      data,
      timeout: params.timeout
    })
      .then(function (response) {
        success(response.data)
      })
      .catch(function (error) {
        if (error.response) {
          success(error.response.data)
        } else {
          fail(error.message || 'unknown ajax error')
        }
      })
  }
})
  • for mixed WebSocket & Ajax communication mode, you need both parameters (io and $ || ajax)
  • no_sockets parameter was removed
  • use_jquery parameter was removed

This allows you to control which modules you need and avoids Webpack dependency detection issues.

Options

Options you can pass to the QEWD({ ... }) instance (see examples) with their default values and a short description:

{
  // application module name
  application: 'unknown',
  // socket.io-client module (optional, required for WebSockets communication)
  io: undefined,
  // jquery module (optional, required for Ajax communication using jQuery's $.ajax)
  $: undefined,
  // specify your own Ajax request handler function, see example above (optional)
  ajax: null,
  // url of QEWD.js server, in the form 'http(s)://<host>:<port>'
  url: null,
  // runtime mode for ewd-client (optional)
  mode: 'development',
  // log each QEWD message sent & received on console (optional)
  log: true,
  // specify custom cookie name to restart the current WebSockets session between page refreshes (optional)
  cookieName: 'ewdSession',
  // use JWT's for sessions (optional)
  jwt: false,
  // decode JWT's in the client (optional)
  jwt_decode: false
}

You'll find further details about these options in the QEWD.js training course.

Use with Vue.js

Below is a small example using Vue.js components.

First, create a new startup app template with vue-cli (or with the most recent @vue/cli version 3.x). This example is just a modification of the standard app template code. If necessary, adjust the url property inside the var qewd to your local settings.

This module adds a $qewd service to the Vue instance. You can then simply communicate with your back-end by invoking this.$qewd.send() in your Vue component methods. Btw, you'll need to define a let self = this to make the Vue component instance available in the send callback because it's not proxied yet inside the callback.

While QEWD.js is starting the WebSocket connection with the back-end, you can also use conditional rendering to hide (parts of) the app view using this.$qewd.vRegistrationCallback(cb). See below, where the App component installs a callback function which QEWD calls when the WebSocket connection state changes. This sets the reactive qewdReady data property and re-renders the view.

Press the "QEWD message test" button to see the plugin back-end communication in action.

import Vue from 'vue'
import App from './App.vue'
import io from 'socket.io-client'
// import both the QEWD class and VueQEWD plugin
import { QEWD, VueQEWD } from 'vue-qewd'
// import axios (optional, in case you need to use ajax mode)
import axios from 'axios'

// instantiate QEWD with your parameters
var qewd = QEWD({
  application: 'qewd-test', // application name
  log: true,
  url: 'http://localhost:8080', // adjust this to your local environment
  io, // use WebSocket communication
  // uncomment the lines below to use axios ajax calls instead of using WebSockets (and remove io parameter)
  // see also part 14 of QEWD training course from page 15 at
  // https://www.slideshare.net/robtweed/ewd-3-training-course-part-14-using-ajax-for-ewdxpress-messages
  /*
  ajax: function (params, success, fail) {
    let data = JSON.stringify(params.data)
    axios({
      url: params.url,
      method: 'post',
      headers: {
        'Content-Type': params.contentType
      },
      data,
      timeout: params.timeout
    })
      .then(function (response) {
        success(response.data)
      })
      .catch(function (error) {
        if (error.response) {
          success(error.response.data)
        } else {
          fail(error.message || 'unknown ajax error')
        }
      })
  }
  */
});

// let Vue know you want to use the plugin
Vue.use(VueQEWD, { qewd });

// create your Vue instance
new Vue({
  el: '#app',
  render: h => h(App)
})

Next, create a default App.vue component:

<template>
  <div id="app">
    <template v-if="qewdReady">
      <img src="./assets/logo.png">
      <h1>{{ msg }}</h1>
      <h2>Essential Links</h2>
    <ul>
      <li><a href="https://vuejs.org" target="_blank">Core Docs</a></li>
      <li><a href="https://forum.vuejs.org" target="_blank">Forum</a></li>
      <li><a href="https://gitter.im/vuejs/vue" target="_blank">Gitter Chat</a></li>
      <li><a href="https://twitter.com/vuejs" target="_blank">Twitter</a></li>
    </ul>
    <h2>Ecosystem</h2>
    <ul>
      <li><a href="http://router.vuejs.org/" target="_blank">vue-router</a></li>
      <li><a href="http://vuex.vuejs.org/" target="_blank">vuex</a></li>
      <li><a href="http://vue-loader.vuejs.org/" target="_blank">vue-loader</a></li>
      <li><a href="https://github.com/vuejs/awesome-vue" target="_blank">awesome-vue</a></li>
    </ul>
    <button @click="testing">QEWD message test</button>
  </template>
  <template v-else>
    <img src="./assets/logo.png">
    <h2>Starting application, please wait ...</h2>
  </template>
  </div>
</template>

<script>
export default {
  name: 'app',
  mounted: function() {
    var self = this;
    // monitor when QEWD is ready
    this.$qewd.vRegistrationCallback(function(registered) {
      self.qewdReady = registered; //
    });
    // start the QEWD WebSockets connection ...
    this.$qewd.vueStart();
  },
  data () {
    return {
      qewdReady: false,
      msg: 'Welcome to Your Vue.js App'
    }
  },
  methods: {
    testing: function() {
      let messageObj = {
        type: 'test',
        params: {
          text: 'a Vue.js test message for QEWD'
        }
      };
      let self = this;
      this.$qewd.send(messageObj, function(messageObj) {
        self.msg = messageObj.message.text;
      });
    }
  }
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}

h1, h2 {
  font-weight: normal;
}

ul {
  list-style-type: none;
  padding: 0;
}

li {
  display: inline-block;
  margin: 0 10px;
}

a {
  color: #42b983;
}
</style>

Next, create a qewd-test.js module in your QEWD back-end server with a test handler returning a simple test message (see below).

module.exports = {
  handlers: {
    test: function(messageObj, session, send, finished) {
      var incomingText = messageObj.params.text;
      var d = new Date();
      finished({text: 'You sent: ' + incomingText + ' at ' + d.toUTCString()});
    }
  }
};

Next, you'll need to install one dependency the QEWD client needs to build it's WebSockets connection to the QEWD.js server back-end:

npm i socket.io-client --save

Finally, run your Vue.js test app with:

npm run dev

Tip: to avoid Webpack errors (requiring both socket.io-client and jquery to be installed), include the module(s) you need as (at least development) dependency in your Vue.js project, e.g.:

npm i socket.io-client
npm i -D jquery

Use with Nuxt.js

If you want to build Vue.js apps using SSR (server-side rendering), you can use vue-qewd inside a Nuxt.js project (template). You need to define vue-qewd first as a plugin for your Nuxt.js project.

Create a vue-qewd.js file inside your /plugins directory:

import Vue from 'vue'
import io from 'socket.io-client'
// import both the QEWD class and VueQEWD plugin
import { QEWD, VueQEWD } from 'vue-qewd'

// instantiate QEWD with your parameters
var qewd = QEWD({
  application: 'qewd-test', // application name
  log: true,
  // adjust this to your local environment
  // using environment vars defined in nuxt.config.js
  url: 'http://' + process.env.qewdHost + ':' + process.env.qewdPort,
  io,
  // use a custom cookie in the browser
  cookieName: 'qwt'
});

// let Vue know you want to use the plugin
Vue.use(VueQEWD, { qewd })

Inside your nuxt.config.js, add vue-qewd.js to the plugins array, e.g.:

module.exports = {
  env: {
    qewdHost: process.env.QEWD_HOST || 'localhost',
    qewdPort: process.env.QEWD_PORT || '8080'
  },
  server: {
    port: 3000, // default: 3000
    host: '0.0.0.0' // default: localhost
  },

  ...

  plugins: [
    '~/plugins/vuetify.js',
    '~/plugins/vue-qewd.js'
  ],

  ...

You can leverage QEWD.js's cookie mechanism to reconnect the WebSocket session automatically between complete page refreshes in Nuxt.js: it's recommended to launch the QEWD.js client from the mounted hook in an Application layout file, e.g. inside /layouts/default.vue you can add QEWD like this:

<template>
  <v-app dark>
  ...
  </v-app>
</template>

<script>
  export default {
    data () {
      return {
        qewdReady: false,
        sessionExpired: false,
        ...
      }
    },
    mounted: function () {
      var self = this
      // monitor when QEWD is ready
      this.$qewd.vRegistrationCallback(function (registered, msgType) {
        console.log('registration callback: ', registered, msgType)
        self.qewdReady = registered
        // preserve session across page refreshes & switches
        if (registered) {
          self.sessionExpired = false
          if (msgType === 'ewd-registered') {
            self.$qewd.setCookie('qwt')
          }
        } else {
          if (msgType === 'socketDisconnected') {
            self.sessionExpired = true
          }
        }
      })
      // start the QEWD WebSockets connection ...
      this.$qewd.vueStart()
    },
    methods: {
      ...
    }
  }
</script>

Btw, this example uses the Vuetify framework to build a nice UI very easily using components.

Next, you can use this.$qewd in all your page methods as usual.

License

Copyright (c) 2019 Stabe nv,
Hofstade, Oost-Vlaanderen, BE
All rights reserved

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.