Fun with Svelte and uibuilder

After a recent announcement about the use of Svelte, it looked interesting enough to see how easy it might be to use with uibuilder.

As it happens - pretty easy :grin:

  1. Create a new uibuilder instance and change the url to svelte (or whatever you want). Click on Deploy.

  2. Install the default svelte template to ~/.node-red/uibuilder/svelte with the command npx degit sveltejs/template ~/.node-red/uibuilder/svelte

  3. Make some very minor changes to the rollup config: Just change lines 42 and 72 to point to the dist folder instead of public.

  4. Rename the public folder to dist and remove the build sub-folder (it gets recreated).

Note that you will need to restart node-red at some point now - sorry about that, it is the way that uibuilder currently decides whether to serve up the src or dist folder. I'll fix that in the future.

  1. Change the build/index.html - noting the leading . or .. added to the various resources:
<!DOCTYPE html><html lang="en"><head>
	<meta charset='utf-8'>
	<meta name='viewport' content='width=device-width,initial-scale=1'>

	<title>Svelte app</title>

	<link rel='icon' type='image/png' href='./favicon.png'>
	<link rel='stylesheet' href='./global.css'>
	<link rel='stylesheet' href='./build/bundle.css'>

    <script defer src="../uibuilder/vendor/socket.io/socket.io.js"></script>
    <script defer src="./uibuilderfe.js"></script> <!-- dev version -->
	<script defer src='./build/bundle.js'></script>
</head><body>
</body></html>

And in App.svelte:

<script>

    import { onMount } from 'svelte';
    onMount(() => {
        uibuilder.start()

        uibuilder.onChange('msg', function(msg){
            console.info('msg received from Node-RED server:', msg)
            nrMsg = msg.payload
        })

    })

    let myGreeting = 'Hello there!'
    let nrMsg = ''
</script>

<h1>Svelte + uibuilder</h1>
<p>{myGreeting}</p>
<button on:click={uibuilder.eventSend} data-greeting="{myGreeting}" data-something="this is something">
	Click Me
</button>
<pre>{nrMsg}</pre>
  1. cd ~/.node-red/uibuilder/svelte && npm install && npm run dev

    Note that the dev process creates its own web server but you should ignore that.

  2. Now load the uibuilder page with http://127.0.0.1:1880/svelte/ (or wherever yours ends up)

    Marvel at the amazing dynamic, data-driven web app you just made!


OK, so not the most amazing thing. But lets note a couple of important points.

  • Make a change to the text in the App.svelte page and save it - notice anything on your web page?

    Yup, it changed without you having to reload it! Just like Svelte's own dev server :grin:

  • Attach a debug node to the output of your uibuilder node. Make sure it is set to show the whole msg object. Now click on the button on your page. Notice that you get a message just by clicking the button, no code required (other than the HTML for the button itself).

    That uses the new eventSend function in uibuilder v3.2

    Note how the data-xxxx attributes are sent back to node-red in the payload, one of which is dynamic thanks to Svelte. Also note that the msg.uibDomEvent.sourceId in node-red contains the text of the button. Try adding an id attribute to the button to see what difference it makes.

  • Send a msg to the uibuilder node and note how the payload appears on the page

    5 lines of code in total to do that :grin:

19 lines of actual code for a simple, data-driven web page. Not too bad I think.


When I get a chance, I will create a GitHub repository with a uibuilder-specific Svelte template to get rid of some of the above steps.

I will also be adding some features to uibuilder in a future release that will make installing your own (or anyone elses) templates to a uibuilder instance. Also, there will be an install and a build button. So that most of the above steps will be reduced to a couple of clicks. These changes will help anyone who needs a build step for their web app, not just for Svelte users.

6 Likes

Hi Julian, I am pretty much interested in testing uibuilder + Svelte, so this was the post of my dreams. Thank you so much for finding the time to share.

The greeting screenshot shows it is working.

I just had to adapt the target folders since I am using projects in Node-RED.

I briefly describe what else I did differently as it migth be useful for more people.

Step #3, about changing the config of /uibuilder/svelte/rollup.config file

Line numbers were not the same, so I share a screenshot of the lines to be changed

j-01

As instructed I changed public to dist

Step #5, about changing /build/index.html. Well, the sub-folder /build folder was deleted in step #4, so I assumed that the goal was to change instead /dist/index.html

Just this couple of small changes and voila ! I can now learn Svelte and practice with uibuilder.

3 Likes

Hello Justin and Andrei,
@Andrei do you also use NR on a docker container by any chance?

Because when I try Svelte, I get very weird results:

192.168.1.236/:1 Refused to apply style from 'http://192.168.1.236:1880/svelte/build/bundle.css' because its MIME type ('text/html') is not a supported stylesheet MIME type, and strict MIME checking is enabled.
App.svelte:15 <App> was created with unknown prop 'name'
(anonymous) @ App.svelte:15
instance @ App.svelte:15
init @ index.mjs:1473
App @ App.svelte:15
(anonymous) @ main.js:3
(anonymous) @ main.js:8
bundle.js:2 GET http://192.168.1.236:35729/livereload.js?snipver=1 net::ERR_CONNECTION_REFUSED
(anonymous) @ bundle.js:2
(anonymous) @ bundle.js:2

Button is not working of course

And the uibuilder folder menu can see (edit?) all node_modules:
image

BTW, for future readers who might get stuck with NR in a container:
/data/uibuilder replaces ~/.node-red/uibuilder

The mime-type issue is usually because you've been a bit slack with the specification of your CSS links. Check the default template index.html file for the exact syntax. This is because uibuilder applies the "no-sniff" setting for security best practice.