-
-
Notifications
You must be signed in to change notification settings - Fork 88
Load Vue (v2 or v3) components without a build step (modern browsers only)
Updated 2023-01-10: Updated for uibuilder v5/v6.
In the WIKI article Dynamically load .vue files without a build step, we show you how to load .vue
files without needing to build them (Vue v2 only, for v3, see this page using vue3-sfc-loader.
Note that this approach also works with Vue v3 as well as v2.
In this article, we show you how to use a modern browser to do something similar using HTML modules
.
In order to do this, you will need to write the Vue component in pure JavaScript.
The following is a Vue v3 example. Vue v2 has a different syntax for setup but the HTML and component would be the same.
export default {
template: `
<div>
<p>Ooh, my very own Vue component!</p>
<p>A component counter: {{ count }} <button @click="count++">Count</button></p>
</div>
`,
data() {
return { count: 0 }
},
}
To load this, in your app javascript file:
// @ts-nocheck
import '../uibuilder/uibuilder.esm.min.js' // Adds `uibuilder` and `$` to globals
// For Vue v3
// import { createApp } from '../uibuilder/vendor/vue/dist/vue.esm.browser.js' // Dev ver local install. Chg to .min.js for prod
import { createApp } from 'https://cdn.jsdelivr.net/npm/vue@3.2.45/dist/vue.esm-browser.js' // As above but loaded remotely
// Import the custom component directly (Note that it is a .js file, not a .vue file)
import MyComponent from './mycomponent.js'
// Using the Vue options API style for beginner simplicity
// No need to pre-define Quasar's $q when working with the options API
const app = createApp({
// Define Vue reactive variables
data() { return {
message: 'Hello Vue!',
count: 0,
lastMsgRecvd: '[Nothing]',
input1: '',
} },
components: {
mycomponent: MyComponent
},
// Dynamic data
computed: {
// This is auto-recalculated by Vue when lastMsgRecvd changes
formatLastRcvd() {
const lastMsgRecvd = this.lastMsgRecvd
if (typeof lastMsgRecvd === 'string') return 'Last Message Received = ' + lastMsgRecvd
return 'Last Message Received = ' + uibuilder.syntaxHighlight(lastMsgRecvd)
},
},
// Supporting functions
methods: {
// Use the uib helper function to send something to NR
doEvent(event) { uibuilder.eventSend(event) },
/** Runs when the change event for the source field is fired
* @param {InputEvent} event The event object is passed by the browser automatically
*/
doInputChange(event) {
console.log('input1 text has changed: ', event.target.value )
// Send the new text to Node-RED
uibuilder.send({
'topic': 'input1-changed',
'payload': event.target.value,
})
},
},
// Lifecycle hooks
mounted() {
// If msg changes - msg is updated when a standard msg is received from Node-RED
uibuilder.onChange('msg', (msg) => {
console.log('>> msg recvd >>', msg, this)
this.lastMsgRecvd = msg
})
},
})
app.mount('#app')
<!doctype html>
<html lang="en"><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Vue3 as EMS with new uib client - Node-RED uibuilder</title>
<meta name="description" content="Node-RED uibuilder - Vue3 as ESM with new uib client">
<link rel="icon" href="./images/node-blue.ico">
<!-- Your own CSS -->
<link type="text/css" rel="stylesheet" href="./index.css" media="all">
<!-- NOTE that this is loaded as a MODULE & other libraries loaded by it -->
<script type="module" async src="./index.js">/* Imports uibuilder + your custom code */</script>
</head><body class="uib">
<div id="app">
<h1 style="margin-bottom:.1em;">Vue v3 App Using New uibuilder ESM Client - v6.1.0</h1>
<div style="margin-bottom:1em;">Loads a Vue component directly without a build step</div>
<div id="more"><!-- '#more' is used as a parent for dynamic content in examples --></div>
<mycomponent></mycomponent>
<p>
<button @click="doEvent" data-mything="This is a thing" title="This is sent back to Node-RED">
Click to send msg to Node-RED
</button>
</p>
<p>
<label for="input1">This is sent to Node-RED when you exit it: </label>
<input v-model="input1" @change="doInputChange" id="input1" type="text" placeholder="Type text then exit field">
</p>
<pre id="msg" v-html="formatLastRcvd" class="syntax-highlight">Waiting for a message from Node-RED</pre>
</div>
<script nomodule>
document.getElementById("app").innerHTML = "Your browser doesn't support JavaScript modules :(";
</script>
</body></html>
Note how only 1 js file is loaded and as type="module"
. Without this, the above will not work. Also note the nomodule
entry for telling users that this doesn't work with older browsers (IE11, we're looking at you!). Other libraries and the custom component are imported in that file.
http-vue-loader and vue3-sfc-loader are already mentioned and allow you to directly load .vue
files.
Another alternative is to use a "build step". This uses a build tool such as Snowpack, Webpack, Rollup, etc. to build the component. This needs an extension to the chosen build tool that understands .vue
files and "compiles" them to a stand-alone javascript file that you either load via a script tag in your HTML or fall back to in the nomodule
part of your HTML (using the module version above for browsers that support them):
<script nomodule src="/dist/build.js"></script>
Of course, if using a build step, you might choose not to use modules at all. However, they are the future of JavaScript so are worth getting to grips with.
Build tools may also be able to output multiple versions. So if you are going to the bother of setting one up, maybe consider outputting both pre-compiled module and non-module versions. Module versions are often designated with esm
(ECMA Script Module) and non-module versions umd
(Universal Module Definition). IIFE (Immediately Invoked Function Expression) is another acronym sometimes mentioned, a library built with IIFE can be loaded directly in an HTML <script src="...">
tag.
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)