Uibuilder with Menu

Sure, but you have to update the cache everytime you update the source.

especially with big libraries

This is where the problem starts, no? :wink:

Strictly speaking, you update the appcache file, the browser then updates the cache. All it needs is another space adding to a line.

I'm thinking that another button in the uibuilder config ui might be used to update/rebuild the file.

Well, lets remember that we are walking a tightrope here. On one hand try to make it as easy as possible for beginners, on the other trying to keep things to a reasonable size.

In my view, the large size of Vue/bootstrap is justified here because of just how easy it makes it to create a nice looking page with virtually no boilerplate. It is still a LOT more performant than Dashboard - certainly on mobile devices.

But if you want to go to the other extreme, uibuilder lets you and will support you :smiley_cat: Strip the libraries out and manipulate the DOM by hand - not that difficult.

uibuilder is really small, vuejs is somewhat larger yes, but then again, looking at work; servicenow - pages easily go up to 7MB per uncached pageload (and they all are, unbelievable), talking about unusable :grimacing:

uibuilder works quite nicely and performant for me with vuejs ofcourse this is mickeymouse stuff for the home, I can live without a cache. Thanks again for all your work.

1 Like

Yes, I keep looking at SharePoint and that is also horrible!

Hi,
Do you have an example with a menu and routing please?

@martynwheeler can I suggest you start a new thread please. This on is on a slightly different subject and is 10 months old.

As it happens, I have been playing with uibuilder + router so might be able to snip some example code for you (its not pretty so maybe a thread on this would help us both & we can keep our fingers crossed for our resident expert Lena chipping in :crossed_fingers:)

Sorry for the inconvenience @Steve-Mcl, but @martynwheeler is indeed right. I added that message knowing Iā€™d likely forget, and Iā€™ve the code lying around. All I have to do is push it to a github repository, which is why that ā€œnode to selfā€ message was for, and the request to remind me. Iā€™ll do so when I boot my laptop later.

Apologies. I just seen a 10m old thread resurrected with a slightly differing subject matter so as most responsible admins do, suggested a new thread (in the interest of keeping the forum sane). Not a problem.

No that's okay. I saw it in my email, with the full response on the post it was responding too, included for brevity below:

So that was a clear case of "I'm likely going to forget this", but if someone pokes me on it I will remember and do it whenever. And clearly it got out of my mind for over 10 months :slight_smile:
And I still have that code on my laptop, I think it's in a local git repo, committed but never pushed, not even locally, let alone to upstream. (Like half of my projects that have a TODO not somewhere that says "check this into git")

1 Like

Okay here you go:


Let me start this off with a couple comments. You can see this in use by taking a uibuilder node and setting it up on a URL, then go to the src directory of that node, and dump all the contents from this repository's src directory in it.
When going through the files, start with index.html. Scroll down to line 63-ish. The order of those included files matter. The addresses for these can be acquired through the use of uibindex on the Uibuilder node. For this setup to work, you need to install a couple frontend libraries on top of the default vue and bootstrap-vue/bootstrap: http-vue-loader, vue-router and vuex. The exact addresses to use can be seen through the show detailed information button on the uibuilder node, which leads you to the aforementioned uibindex. If you've set up authentication for httpAdmin in the settings file, you might (will) run into problems viewing those. I'm working on a bugfix for that, but it depends on my energy levels and mental health how long it will take to have those fixes rolled out. The addresses in the index.html file in this repository assume you've Node-RED running on the default paths in the settings file, and that your uibuilder URL doesn't include any slashes in the address.

The order in which these libraries are loaded is important, though you can follow the setup I've in here.
At line 69, you see the inclusion of Vue. For this to work in the way I've created this demonstration flows, you do this all without a build step, so what you code is what is loaded by the browser directly. For that, you need a version of the Vue library with an included compiler in the runtime, whether that's the dev or the production version is your choice. I usually set it to dev, until it's 100% ready then switch to prod. Dev allows easy debugging in the browser using the VueJS browser extension, hence why I use it until the very end.

At line 87, the index.js script is added. This is the entry point of all the "magic" that's happening here. In order for the browser to be able to work with imports from the index.js script, and further imports down the road, you've to add type="module" to the script tag.

In the index.js, on lines 19-20 you can see those imports in use. The first loads the definitions for Vuex, the state store that I use here, and the second loads the definitions for the router, which is probably what you're interested in most.
As you can see here and in router.js, I make use of httpVueLoader to load so called Single File Components over http into the system. This file shows both immediate loading, as well as the lazy loading mentioned earlier in this topic. For example, const HeaderMenu = httpVueLoader('./components/HeaderMenu.vue'); will immediately load the HeaderMenu.vue component, and makes it available in the variable HeaderMenu. This file by the way includes the menu, so it's worth taking a look at that, I'm coming back to it in a moment. To get lazy loading to work, you create an arrow function that resolves a promise inside, and within the Promise.resolve you put the httpVueLoader call. That way, the file is only included once that endpoint is called. It's a good way to pace the resources being loaded. You can see this on line 26: () => Promise.resolve(httpVueLoader('./components/Room.vue'))
It's interesting here to note that inside httpVueLoader calls you should use paths relative to the current file. Since router.js is located on the outermost level within the src directory, you use the full relative path to child folders, but for example within components/UsageInformation.vue another component is included which is references as ./JSONSyntaxHighlight.vue as it is also located in that same components folder, and that's the point you're looking from.

Next step is components/HeaderMenu.vue, that's the menu that shows. It's a simple bootstrap/bootstrap-vue menu, but it uses <b-nav-item> with a to attribute. If you set it as this, you can use the name property in an object that matches the name from the router.js file.

You might notice that in all the .vue files within the script module.exports = { ... } syntax is used, but in the JS files export default { ... }. That's because of the browser needing the export default { ... } syntax for the js files that are imported (think back to the type="module" part in the index.html file), but for httpVueRouter to work it needs the module.exports = { ... } syntax instead.
That is confusing, and it will likely lead you to strange errors if you forget that for a moment. If you decide to go for a build step instead (for example through webpack) you won't need to deal with those peculiarities as httpVueLoader isn't needed for that and you get compiled files for ES5 that won't have the type="module" rules to comply with either.

Depending on how you set things up, httpVueLoader is also capable of dealing with Single File Components with SCSS styling, TypeScript script tags, or something like Pug for the templating. That's all beyond the scope of this demo, so none of that is included, but know that it is possible.
I hope this long thing helps you get started. Good luck!

3 Likes