-
-
Notifications
You must be signed in to change notification settings - Fork 86
Basic Vite Vue 3 TypeScript App
Editors note: Please remember that if you are using Vite's live dev server to run your uibuilder app, you will need to give the uibuilder client a hint as to the correct Socket.IO namespace. This is done by including the namespace in a
start
function early in your custom code. For example, if your uibuilder url isaa
and you are testing locally,uibuilder.start({ioNamespace:'http://localhost:1880/aa'})
. You can and should remove this when running normally.See the documentation for details.
In this article, a app would build with the combination of Vite
+ Vue 3
+ TypeScript
+ Uibuilder
.
The concept of Typescript, Vue 3 plugin, Vue 3 CompositionApi, Vue 3 inject and provide would be touched.
-
Add
uibuilder
node in your flow. -
Double click this node and change Properties
Name
andURL
tovue3-app
-
Expand
Advanced Settings
: set Template todist
instead ofsrc
-
Save and deploy
Change directory to uibuilder
// path: node-red setting projects enabled
pathto/.node-red/projects/project-name/uibuilder/
// path: node-red setting projects disabled
pathto/.node-red/uibuilder/
Note: Remember that you can also now change the uibRoot
folder (which defaults to ~/.node-red/uibuilder/
when not using node-red projects) to any accessible folder by making a change to the settings.js file.
Create a vite project
With npm:
$ npm create vite@latest
With yarn:
$ yarn create vite
Then following the prompts, for this article we make choice as below.
$ Project name: vue3-app
$ Select a framework: > vue
$ Select a variant: vue-ts
Done. Now run
$ cd vue3-app
File structure is:
. //Vue3-app
├── README.md
├── index.html
├── package.json
├── public
│ └── favicon.ico
├── src
│ ├── App.vue
│ ├── assets
│ │ └── logo.png
│ ├── components
│ │ └── HelloWorld.vue
│ ├── env.d.ts
│ └── main.ts //entry
├── tsconfig.json
└── vite.config.ts // vite configuration
With npm:
Install uibuilder
$ npm install node-red-contrib-uibuilder
Note: This is better done via Node-RED's palette manager.
Install uibuilder dependency socket.io-client
$ npm install socket.io-client
WARNING: Take care to match the client version that uibuilder uses otherwise you may get hard to analyse problems. If you can, avoid installing the client and instead use the existing client that uibuilder has already installed. However, this requires some tweaking of your build.
Install plugin legacy in case your browser doesn't support Navite ESM( This is baseline for vite ). You can skip this if your browser support Native ESM (which should be most current browsers).
$ npm install @vitejs/plugin-legacy
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// optional, the plugin-legacy is used to support legacy brower withou Native ESM.
import legacy from '@vitejs/plugin-legacy'
// https://vitejs.dev/config/
export default defineConfig({
// set the base url as './', the default base url is '/'.
// In our approach, the vue3-app is host by node-red.
// The '/' would be intepreted into 'http://localhost:1880' which cause wrong url issue for the script, style , image and icon for index.html in dist folder.
// While './' would be intepreted into 'http://localhost:1880/vue3-app'
base: './',
plugins: [
vue(),
// optional, the plugin-legacy is used to support legacy brower withou Native ESM.
legacy({
targets: ['defaults', 'not IE 11']
})
],
// This a walkaround to let the vite solve the uibuilderfe.js correctly
optimizeDeps: {
include: [
'node-red-contrib-uibuilder/front-end/src/uibuilderfe.js',
]
},
// The proxy is used to provide node-red connection in developing mode. 'yarn dev'
server:{
proxy:{
'/uibuilder':{
target: "http://localhost:1880/uibuilder",
changeOrigin: true,
ws:true,
rewrite: (path)=>path.replace(/\/uibuilder/, ''),
},
}
}
})
Create src/interface folder
$ mkdir src/interface
Add IData.ts
interface IData {
topic: string
payload: string
// you can define more memeber here according to your model
}
export default IData;
Create plugin folder
$ mkdir src/plugin
Add uibuilderPlugin.ts. In this plugin, all uibuilder related data
and method
is put inside. plugin. Data and method is registered vie Vue3 provide and inject pattern. It's convenient to receive message or send message by injection in any component. A hub for all datum. A compact version of vuex store instance
.
import { App, provide, reactive, ref } from 'vue'
// this line is used to ignore tsc since uibuilderfe.js is not providing types.
// @ts-ignore
import uibuilder from 'node-red-contrib-uibuilder/front-end/src/uibuilderfe.js'
import IData from '../interface/IData';
export default {
install: (app: App, options: {nameSpace:string}) => {
/* our code for the plugin goes here
app is the result of createApp()
options is user options passed in. We pass the uibuilder node url here for connection */
// get nameSpace the same as uibuilder node url. eg: '/vue3-app' - only needed for the Vite dev server
const { nameSpace } = options;
// defien the reactive data used for this app
const reactiveAsyncData = reactive<IData>({
topic: '',
payload: '',
// define more here
});
// provide asyncData global
app.provide('asyncData', reactiveAsyncData);
// messageHandler
const messageHandler = () => {
uibuilder.onChange('msg', (newValue:{topic:string, payload:string}) =>{
reactiveAsyncData.topic = newValue.topic;
reactiveAsyncData.payload = newValue.payload;
// topic logic here
switch(newValue.topic){
}
})
}
// start messageHandler
messageHandler();
// start uibuilder instance
uibuilder.start(nameSpace);
/* send message back to node-red*/
const send2NR = (topic: string, payload: string):void => {
console.log(topic, payload);
uibuilder.send({
'topic': topic,
'payload': payload
});
}
/* send control command to node-red*/
app.provide("send2NR", send2NR);
}
}
In this component, we display the received message from node-red and can also send back message with specific topic and payload. Have fun.
// src/main.ts
import { createApp } from 'vue'
import App from './App.vue'
import uibuilderPlugin from './plugin/uibuilderPlugin';
const app = createApp(App);
// use uibuilderPlugin, we pass the nameSpace for uibuilder.start('/vue-app') here
app.use(uibuilderPlugin, { 'nameSpace': '/vue3-app' });
// mount app
app.mount('#app')
// src/components/Helloworld.vue
<script setup lang="ts">
import { ref, inject } from 'vue'
import IData from '../interface/IData'
defineProps<{
msg: String,
}>()
// inject method 'send2NR' from plugin uibuilderPlugin
const send2NR = inject('send2NR') as (topic: string, payload:string) => void;
// inject data 'asyncData' from plugin uibuilderPlugin
const asyncData = inject('asyncData') as IData;
// local variable for topic to send
const topic = ref('');
// local variable for payload in the textarea to send
const payload = ref('');
const count = ref(0);
</script>
<template>
<h1>{{ msg }} </h1>
<div className="container">
<div className="box">
<h2>Received</h2>
<input className="box-topic" readonly type="text" placeholder="Received Topic" v-model="asyncData.topic"/>
<textarea className="box-message" readonly type="text" placeholder="Received Payload" v-model="asyncData.payload" />
</div>
<div className="box">
<h2>Send</h2>
<input className="box-topic" type="text" placeholder="type topic" v-model="topic"/>
<textarea className="box-message" type="text" placeholder="press enter to send" v-model="payload" @keyup.enter.exact="send2NR(topic, payload)"/>
</div>
</div>
<br/>
<br/>
<button type="button" @click="count++">count is: {{ count }}</button>
<p>
Recommended IDE setup:
<a href="https://code.visualstudio.com/" target="_blank">VSCode</a>
+
<a href="https://github.com/johnsoncodehk/volar" target="_blank">Volar</a>
</p>
<p>
<a href="https://vitejs.dev/guide/features.html" target="_blank">
Vite Documentation
</a>
|
<a href="https://v3.vuejs.org/" target="_blank">Vue 3 Documentation</a>
</p>
<p>
Edit
<code>components/HelloWorld.vue</code> to test hot module replacement.
</p>
</template>
<style scoped>
a {
color: #42b983;
}
.container {
display: inline;
text-align: center;
}
.box {
font: 15px arial, sans-serif;
border-style: solid;
border-width: 1px;
padding: 10px;
border-radius: 5px;
display: inline-block;
}
.box-topic {
height: 50px;
font: 20px bold, arial, sans-serif;
width: 95%;
padding: 5px;
}
.box-message {
height: 200px;
font: 17px arial, sans-serif;
width: 95%;
padding: 5px;
}
</style>
With npm
$ npm run dev
With yarn
$ yarn dev
Modify and check the hot update in the http://localhost:3000. Lightening fast!
With npm
$ npm run build
With yarn
$ yarn build
The static file is generated in dist folder.
File structure
. //vue3-app
├── README.md
├── dist
│ ├── assets
│ │ ├── index.54df34ff.js
│ │ ├── index.effd24ec.css
│ │ ├── logo.03d6d6da.png
│ │ └── vendor.c0cb906b.js
│ ├── favicon.ico
│ └── index.html
├── index.html
├── package.json
├── public
│ └── favicon.ico
├── src
│ ├── App.vue
│ ├── assets
│ │ └── logo.png
│ ├── components
│ │ └── HelloWorld.vue
│ ├── env.d.ts
│ ├── interface
│ │ └── IData.ts
│ ├── main.ts
│ └── plugin
│ └── uibuilderPlugin.ts
├── tsconfig.json
├── vite.config.ts
└── yarn.lock
package.json
{
"name": "vue3-app",
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "vue-tsc --noEmit && vite build",
"preview": "vite preview"
},
"dependencies": {
"node-red-contrib-uibuilder": "^4.1.4",
"socket.io-client": "^4.4.1",
"vue": "^3.2.25"
},
"devDependencies": {
"@vitejs/plugin-vue": "^2.0.0",
"typescript": "^4.4.4",
"vite": "^2.7.2",
"vue-tsc": "^0.29.8"
}
}
For the detail source code, you can check this link node-red-uibuilder-vite-vue3-typescript-example. You can create issue in this repo if you have any question or problem. Happy coding.
Please feel free to add comments to the page (clearly mark with your initials & please add a commit msg so we know what has changed). You can contact me in the Discourse forum, or raise an issue here in GitHub! I will make sure all comments & suggestions are represented here.
-
Walkthrough 🔗 Getting started
-
In Progress and To Do 🔗 What's coming up for uibuilder?
-
Awesome uibuilder Examples, tutorials, templates and references.
-
How To
- How to send data when a client connects or reloads the page
- Send messages to a specific client
- Cache & Replay Messages
- Cache without a helper node
- Use webpack to optimise front-end libraries and code
- How to contribute & coding standards
- How to use NGINX as a proxy for Node-RED
- How to manage packages manually
- How to upload a file from the browser to Node-RED
-
Vanilla HTML/JavaScript examples
-
VueJS general hints, tips and examples
- Load Vue (v2 or v3) components without a build step (modern browsers only)
- How to use webpack with VueJS (or other frameworks)
- Awesome VueJS - Tips, info & libraries for working with Vue
- Components that work
-
VueJS v3 hints, tips and examples
-
VueJS v2 hints, tips and examples
- Dynamically load .vue files without a build step (Vue v2)
- Really Simple Example (Quote of the Day)
- Example charts using Chartkick, Chart.js, Google
- Example Gauge using vue-svg-gauge
- Example charts using ApexCharts
- Example chart using Vue-ECharts
- Example: debug messages using uibuilder & Vue
- Example: knob/gauge widget for uibuilder & Vue
- Example: Embedded video player using VideoJS
- Simple Button Acknowledgement Example Thanks to ringmybell
- Using Vue-Router without a build step Thanks to AFelix
- Vue Canvas Knob Component Thanks to Klaus Zerbe
-
Examples for other frameworks (check version before trying)
- Basic jQuery example - Updated for uibuilder v6.1
- ReactJS with no build - updated for uibuilder v5/6
-
Examples for other frameworks (may not work, out-of-date)
-
Outdated Pages (Historic only)
- v1 Examples (these need updating to uibuilder v2/v3/v4/v5)