Uibuilder Webpack Wiki

Hello,

I've got some questions on the Wiki wrt to this topic :slight_smile:
(Node Red : 2.0.5)
(UiBuilder : 4.1.1)
(copy-webpack-plugin@9.0.1)

https://github.com/TotallyInformation/node-red-contrib-uibuilder/wiki/Using-VueJS-with-Webpack

When following the wiki step-by-step , the following changes had to be made :

  1. webpack.config.dev.js format has changed a bit with the latest versions of webpack-copy-plugin .
plugins: [
        new VueLoaderPlugin(),
        // Copies from wherever to the dist folder
        new CopyWebpackPlugin({
                patterns: [
            {from: './src/index.html'},
            {from: './src/index.css'},
            {from: './src/manifest.json'},
        ]
        }),
    ],

  1. index.js file
  • uibuilder location has changed from "nodes" to "front-end" .
import uibuilder from './../../../node_modules/node-red-contrib-uibuilder/front-end/src/uibuilderfe.js'

3a) index.html file

The socket.io.js as mentioned is not found.

    <script src="/uibuilder/socket.io/socket.io.js"></script>

What works is (this is now default in the default index.html as well)

    <script src="../uibuilder/vendor/socket.io/socket.io.js"></script>

3b) manifest.json not found when building with npm run build.

Solution is to copy a manifest.json file from another uibuilder node (standard template).

3c) changed the uibuilder node in node-red editor , changing template to dist (otherwise the main.js file is not copied to the dist folder, which is needed as the index.html refers to it as "./main.js"

image

4)Question .

There does not seem to be a uibuilder.start() ?
So, after running npm run build in a terminal (.node-red/uibuilder/uitest) , I get the webpage, no errors in the console, however messages not received over socket.io
=> If I enter a uibuilder.start(this) or uibuilder.start() statement in index.js in the created: function() {} hook, I get repeated Bad Request errors.
=> If I enter uibuilder.start('/uitest','../uibuilder/vendor/socket.io'), I get no bad request errors but timeout messages in the console log repeatedly
[uibuilderfe:checkConnect:setTimeout] Socket.IO reconnection attempt. Current delay: 2000
Instance details in node red editor show no abnormality

On point 4) I have some progress.
I had the following output of "npm run build" :

> webpack --config ./webpack.config.dev.js

asset main.js 496 KiB [compared for emit] (name: main)
asset index.html 705 bytes [compared for emit] [from: src/index.html] [copied]
asset manifest.json 358 bytes [compared for emit] [from: src/manifest.json] [copied]
asset index.css 293 bytes [compared for emit] [from: src/index.css] [copied]
runtime modules 1.13 KiB 5 modules
modules by path ../../node_modules/ 217 KiB
  modules by path ../../node_modules/engine.io-client/ 62.9 KiB
    modules by path ../../node_modules/engine.io-client/lib/ 49.2 KiB 10 modules
    modules by path ../../node_modules/engine.io-client/node_modules/ 13.7 KiB 3 modules
  modules by path ../../node_modules/socket.io-client/ 50.3 KiB
    modules by path ../../node_modules/socket.io-client/node_modules/ 26.2 KiB 6 modules
    modules by path ../../node_modules/socket.io-client/lib/*.js 24.1 KiB 5 modules
  modules by path ../../node_modules/engine.io-parser/lib/*.js 19.7 KiB 3 modules
modules by path ./ 229 KiB
  modules by path ./src/ 3.06 KiB 4 modules
  modules by path ./node_modules/ 226 KiB
    ./node_modules/vue/dist/vue.runtime.esm.js 223 KiB [built] [code generated]
    ./node_modules/vue-loader/lib/runtime/componentNormalizer.js 2.71 KiB [built] [code generated]
ws (ignored) 15 bytes [optional] [built] [code generated]
webpack 5.53.0 compiled successfully in 1210 ms

Noticing that ../../node_modules/socket.io-client and ../../node_modules/engine.io-client where modules loaded outside of the root of the project /uibuilder/uitest, and, quite old versions, I installed them with npm install engine.io-client socket.io-client in the project node_modules folder , and linking the original directories, as I don't know how to force webpack to use specific paths.

After rebuilding AND adding uibuilder.start(this) in the index.js , I successfully receive messages in the node.
Not sure whether this make any sense so far .

Thanks for comments/

Summary :

So , to make this work , in summary :slight_smile:

  1. install webpack and dependencies with npm as per the wiki instructions
  2. change webpack.config.dev.js (as per above point 1)
  3. Did not import the uibuilder script in index.js but rather in App.vue (see below)
  4. Did not add any <script source="/uibuilder/socket.io/socket.io.js> in index.html (as webpack build seems to add the module anyway)
  5. manifest.json added and dist chosen as template (as per point 3b) and 3c))
  6. Making sure npm run build includes up-to-date modules of socket.io-client and engine.io-client (some further help needed on how to make this more robust)
  7. added uibuilder import and uibuilder.start(this) to App.vue and mounted() hook respectively as so
    (as the purpose of this exercise here is to use an App.vue file and not index.html)

App.vue

<template>
    <div>
        <h1>Hello World  {{ msgreceived }} </h1>
    </div>
</template>
<script>

import uibuilder from './../../../node_modules/node-red-contrib-uibuilder/front-end/src/uibuilderfe.js'

export default {
data() {
  return {
    msgreceived:""
  }
},
mounted() {
        console.debug('Vue:mounted - setting up uibuilder watchers')
        //console.log(uibuilder)
        uibuilder.start(this)
        // Save confusion by keeping a specific reference to this Vue app
        // If msg changes - msg is updated when a standard msg is received from Node-RED over Socket.IO
        // Note that you can also listen for 'msgsReceived' as they are updated at the same time
        // but newVal relates to the attribute being listened to.
        const app = this;
        uibuilder.onChange('msg', function(msg){
            console.log('Vue:mounted:UIBUILDER: property msg changed! ', msg)
            app.msgreceived = msg.payload
        
        }) // ---- End of uibuilder.onChange() watcher function ---- //
    },
}
</script>

Hi, sorry you had some trauma there :slight_smile:

uibuilder continues to evolve but I haven't updated the WIKI in a while as my focus has been on the code and the built-in technical docs which will eventually replace much of the WIKI.

Couple of points.

  1. I don't think you need the manifest any more. I originally put that in following a discussion some years ago with Dave about speeding up the loading of dashboards. It's old usage is now deprecated by web standards and the new use is only for web workers which I'm not yet using.

  2. You should not be loading different versions of the Socket.Io client. This will end with hard to debug problems. The correct version is the one that matches the Socket.IO server, any other version could fail at any time. You should be using the server and client that is included with uibuilder otherwise there is a very good chance that nothing will work. Socket.Io has gone through several major version upgrades recently and the code for the latest version is quite different in places. uibuilder v4 updated from Socket.Io v2 to v4.

  3. Yes, you need uibuilder.start to start the comms. It is now best to put this into the started section of your Vue app though it does work in the mounted section. It is also a good idea to pass this to it as a single parameter as this tells the library that you are using VueJS and activates some built-in helpers.

    If you ever run start and comms aren't working, check the console for errors, it often means that, for some reason, the library cannot workout what the correct socket.io namepace is.

Please add a new uibuilder node instance to a flow and check out the latest VueJS template code because it has matured somewhat.

@TotallyInformation Thanks for the quick comments , awesome ! No traumas , all fun :slight_smile:

  1. On the socket.io , definitely agree with your comments, still have some questions how to get "npm run build" choose the correct versions . At first sight , I don't have an option of choosing what the build includes (because of my limited knowledge !) BTW, the npm run build now "suddenly" takes a local path :slight_smile:
modules by path ./node_modules/engine.io-client/lib/ 44.4 KiB 12 modules
modules by path ./node_modules/socket.io-client/build/*.js 29.6 KiB 6 modules

This might be because of installing it locally (npm install socket.io-client --save) and logging out/in of the terminal (?) , see packages.json . This is TBC for me .

"dependencies": {
    "bootstrap-vue": "^2.21.2",
    "engine.io": "^5.2.0",
    "socket.io-client": "^4.2.0",
  1. On point 3) You mean the "created" hook, right ?
  2. For reference

Before running the npm run build , this is the setup :

index.html file in src folder

<!doctype html>
<html lang="en"><head>

    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>NodeRED UI Builder Blank template</title>
    <meta name="description" content="Node-RED UI Builder - Blank template">
    <link rel="icon" href="./images/node-blue.ico">

    <link type="text/css" rel="stylesheet" href="./index.css" media="all">

</head><body>
    <div id="app"></div>

    <!--<script src="../uibuilder/vendor/socket.io/socket.io.js"></script>-->
    <!-- Note no leading / -->
    <script src="./main.js" type="text/javascript"></script>


</body></html>

index.js
(Almost nothing in here except the Vue app !)

import Vue from 'vue'
import App from './App.vue'

new Vue({
    el: '#app',
    render: h => h(App),
    mounted: function(){
        const vueApp = this
    }, //

App.vue

<template>
    <div>
         Message Payload : {{ msgreceived }}
   </div>
</template>
<script>

import uibuilder from './../../../node_modules/node-red-contrib-uibuilder/front-end/src/uibuilderfe.js'

export default {
data() {
  return {
    msgreceived:""
  }
},
methods: {
},
created() {
      uibuilder.start(this)
},
mounted() {
        console.debug('Vue:mounted - setting up uibuilder watchers')
        const app = this;
        uibuilder.onChange('msg', function(msg){
            console.log('Vue:mounted:UIBUILDER: property msg changed! ', msg)
            app.msgreceived = msg.payload
        }) // ---- End of uibuilder.onChange() watcher function ---- //

    },

}


</script>

I would actually leave the client socket.io out of the build. Use it as per the default template and it will just work and will pick up the correct version always. You really are not getting any benefit from trying to over work your build process. That will also mean that you don't need to mess with installing things that you really don't need.

Personally, I would actually do the same for Vue and bootstrap-vue. If you need some performance boost (debatable anyway), simply use the .min versions. You can also use the Vue version that excludes the Vue compile functions since you are doing that up front.

If you keep all of the dependent libraries out of your build and use the min versions (uibuilderfe has one as well), you will get pretty much all the same performance bar the very first load (when the browser cache is empty) and can greatly simplify your build step. Just focus on the Vue app and its components.

Revisit in the future if you decide that you need to squeeze a bit more performance out of it. By then you should have more experience and will be able to understand the best way to do things.

Over-optimising up front is never a god idea. Modern browsers and web servers have largely cracked the issues of loading multiple resources and that is why we put the js resources at the end of the html file.

If you really want a performance boost, use a proper web server such as Caddy or NGINX as a reverse proxy, that will give you a boost.

@TotallyInformation Thanks !

To answer my own question on webpack.config.dev.js file and the loading of modules in node_modules of current project directory iso webpack looking for other directories :slight_smile:

Important part for the above is the const path line , and the resolve: part.

(Extract of webpack.config.dev.js)

'use strict'

const { VueLoaderPlugin } = require('vue-loader')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const path = require('path');

module.exports = {
    mode: 'development',
    resolve: {
      modules: [path.resolve(__dirname, 'node_modules'), 'node_modules']
    },
    entry: ['./src/index.js'],

.....