Renderless Vue.js Komponente mit MQTT

Implementierung einer renderless Komponente mit Vue.js und MQTT sowie die Integration in eine statische Webseite.

Etjen Delilovic, 13.03.2023

Einführung

Renderless-Komponenten sind Komponenten, die keine eigene Benutzeroberfläche haben und stattdessen ihre Funktionalität als API bereitstellen, um von anderen Komponenten oder Anwendungen genutzt zu werden. Ein Vorteil dieser Komponenten ist, dass das Aussehen vollständig angepasst werden kann.

In diesem Beitrag wird eine solche Renderless-Komponente erstellt. Als Beispiel dient ein einfaches Kontaktformular, das mittels MQTT die eingegebenen Daten verarbeitet. Durch die Verwendung von MQTT für die Datenverarbeitung wird die Komponente unabhängig vom Backend, das die eingegebenen Daten letztendlich verarbeitet.

Die Anforderungen an die Komponente lauten wie folgt:

  1. Einfache Integration in bestehende Anwendungen.
  2. Uneingeschränkte Anpassungsmöglichkeiten des Designs der Komponente.
  3. Unabhängigkeit von dem Web-Framework, in dem die Komponente verwendet wird.
  4. Backend-Agnostizität, d.h. die Komponente muss mit verschiedenen Backend-Systemen kompatibel sein.

Technologien

Folgende Technologien werden für die Komponente eingesetzt:

  1. Frontend: Vue.js - bietet einen klaren und einfachen Ansatz zur Erstellung von interaktiven Benutzeroberflächen mit wiederverwendbaren und modularisierten Komponenten, was die Entwicklung von Webanwendungen beschleunigt und vereinfacht.
  2. Middleware: MQTT - ein leichtgewichtiges, auf dem Publish-Subscribe-Muster basierendes Protokoll zur Übertragung von Nachrichten zwischen Geräten und Anwendungen in verteilten Systemen.
  3. Backend: Node-RED - browserbasierte Flow-Programmierumgebung, die es Benutzern ermöglicht, Datenflüsse zwischen verschiedenen Geräten und Diensten zu erstellen, zu testen und zu implementieren.
Schematische Darstellung der Architektur

Die Komponente

Als Beispiel nehmen wir ein eifnaches Kontak Formular, welches in eine Statische Webseite eingebettet wrid. Die Homepage von TRX-Base wurde mit Hugo erstellt. #### LINK ZUM BLOG EINTRAG. Statische Seiten haben den Nachteil, dass Sie kein Backend haben welches dynamische Inhalte anzeigen oder verareiten würde. Um dieses Problem zu lösen, nutzt unsere Komponente MQTT als Endpunkt, von wo aus die Nachricht von einem beliebigen Microservice verarbeitet werden kann.

Sourcecode

Der komplette Source Code für diese Komponente ist auf GitHub verfügbar.

git clone https://github.com/trx-base/trx-base-homepage.git

Die Komponente besteht lediglich aus zwei Dateien:

component.js (Vue.js)

/*
Prerequisites:
  <script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
  <script src="https://unpkg.com/mqtt/dist/mqtt.min.js"></script>
*/

export default {
  template: '<slot :data="data" :submit="submit"/>',
  props: {
    mqttHost: String,
    mqttTopic: String
  },
  data() {
    return {
      mqttClient: {},
      data: {
        values: {},
        messages: {
          general: ''
        }
      }

    };
  },
  methods: {
    submit() {
      this.mqttClient.publish(this.submitTopic, JSON.stringify(this.data.values));
      this.data.values = {};
      this.data.messages.general = 'Thank you for reaching out to us. Our team will be in touch with you soon.';
    }
  },
  computed: {
    submitTopic() {
      return this.mqttTopic + '/mqtt-vue-contact-form/submit';
    }
  },
  mounted() {
    // eslint-disable-next-line no-undef
    this.mqttClient = mqtt.connect(this.mqttHost);
  }
};

Als Parameter muss der mqttHostmitgegeben werden. Das ist die URL für den MQTT Broker. In unserem Fall wird das https://unpkg.com/@trx-base/mqtt-vue-contact-formsein.

Außerdem muss das mqttTopic mitgegeben werden. Das ist das Topic unter welchem ein ausgefülltes Kontaktformular im MQTT Broker veröffentlicht wird.

Über den <slot> tag werden die relevanten Daten an den Nutzer der Komponente übergeben. In diesem Fall sind das:

  1. data.values: Die Werte, die im Formular mitgegeben werden. Das sind z.Bsp. Name, Email und die Nachricht. Kann beliebig gestaltet werden.
  2. data.messages: Die Nachrichten, welche der Nutzer der Komponente anzeigen kann. In diesem Fall ist das die Mitteilung wenn ein Formular erfolgreich gesendet wurden (general).
  3. submit: Eine Referenz zur Methode welche die Nachricht schlussendlich an den MQTT Broker übermittelt. Diese Methode kann der Aufrufer Situationsbedingt aufrufen - z.Bsp. wenn ein Knopf gedrückt wurde.

Empfehlung: Die Komponente könnte auch einen optionalen Parameter für die data.messages.general Nachricht übergeben. So kann der Text individualisiert werden, um diesen z.Bsp. in einer anderen Sprache darzustellen.

index.html


<html>
<head>
  <script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
  <script src="https://unpkg.com/mqtt/dist/mqtt.min.js"></script>
  <script type="module"></script>
</head>
<body>
<h1>mqtt-vue-contact-form</h1>
<div id="MqttVueContactForm">
  <Component :mqtt-host="mqttHost" :mqtt-topic="mqttTopic" v-slot="slotProps">
    <label>Name:</label><br />
    <input v-model="slotProps.data.values.name" name="fullName" /><br />

    <label>Email:</label><br />
    <input v-model="slotProps.data.values.email" name="email" /><br />

    <label>Message:</label><br />
    <textarea v-model="slotProps.data.values.message" name="message"></textarea
    ><br />

    <button @click="slotProps.submit">Submit</button>
    <br />
    <div> {{ slotProps.data.messages.general }}</div>
  </Component>
</div>
</body>
<script type="module">
  // import Component from "https://unpkg.com/@trx-base/mqtt-vue-contact-form";  //production
  import Component from "./dist/component.js";

  Vue.createApp({
    components: { Component },
    data() {
      return {
        mqttHost: "wss://public.trxbroker.org/mqtt",
        mqttTopic: "mqtt-vue-contact-form/test"
      };
    },
  }).mount("#MqttVueContactForm");
</script>
</html>

Es werden folgende Java Script libraries geladen:

  1. Vue.js: https://unpkg.com/vue@3/dist/vue.global.prod.js
  2. Mqtt.js: https://unpkg.com/mqtt/dist/mqtt.min.js
  3. Die Komponente selbst: ./dist/component.js- Alternativ kann die Komponente auch per CDN geladen werden: https://unpkg.com/@trx-base/mqtt-vue-contact-form

Dieses index.html dient als Blaupause für die Integration in ein beliebiges Web-Frontend.

Backend

In der Einführung haben wir die Anforderung gestellt, eine Backend-Agnostische Komponente erstellen zu wollen. Die Nachricht wird im MQTT Broker veröffentlicht. Ob und wer die Nachricht schlussendlich verarbeitet, soll für die Komponente nicht von belangen sein.

Der Vorteil von Micro Service Architekturen ist, dass man die Micro Services beliebig miteinander kombinieren kann. Wir haben bereits ein Micro Service, welches Telegram Nachrichten versenden kann. Wir haben auch ein Micro Service, welches Emails versenden kann. Wie können wir diese Micro Services für unsere Kontaktformular Komponente nutzen?

Node-RED

Node-RED ist eine “No-Code” Entwicklungsplattform für das Internet der Dinge (IoT), die auf Node.js basiert. Mit Node-RED können visuelle Flows mit einer einfachen Benutzeroberfläche erstellt werden, die ermöglichen, Daten aus verschiedenen Quellen zu sammeln, zu verarbeiten und zu visualisieren. Node-RED kann in einer Vielzahl von Anwendungen eingesetzt werden, einschließlich Home Automation, Machine-to-Machine-Kommunikation und Datenanalyse.

Hier ist ein Beispiel einer einfachen Node-RED konfiguration, wo übermittelte Formularanfragen sowohl als Telegram Nachricht, als auch als Email versendet werden:

Node-RED Konfiguration für die Verarbeitung der Nachricht.