[uibuilder] how to add and use prism with uibuilder

HI,

I am switching from dashboard to uibuilder and would like to use prism with uibuilder.
I successfully added the prism library using the library manager, my user node-red path is ~/.node-red what should I use in my html instead of the prism sample code below? Maybe Julian can help @TotallyInformation ?

<!DOCTYPE html>
<html>
<head>
	...
	<link href="themes/prism.css" rel="stylesheet" />
</head>
<body>
	...
	<script src="prism.js"></script>
</body>
</html>

I use node-red v2.1.4 and uibuilder v4.1.4


Hi, and welcome to uibuilder :grinning:

All of the vendor front-end libraries are served from ../uibuilder/vendor/<npmModuleName>/ So in your case, most likely ../uibuilder/vendor/prism/.

The actual file references can sometimes take a bit of working out and you can either simply look into the installed package folder or you can look at a CDN to work out what the references are.

In the case of Prism, you can also find out what you need from its package.json file:

So you need <link href="../uibuilder/vendor/prism/themes/prism.css" rel="stylesheet" /> and <script src="../uibuilder/vendor/prism/prism.js"></script>

You can look at the details page in uibuilder as well as it will give you some hints. In this case, it would have told you the correct path for the .js file but not the CSS.

Interestingly, I'd not spotted the style property in package.json before. Now that I know about it and can see that a number of big packages are supporting it, I will add to the backlog to include it in the details page for ease of reference. Nice :mage:


Couple of things to note for when v5 comes along (currently available via the GitHub vNext branch if you want to get ahead of the game).

  • Package installations are on the move. This is one of the breaking changes in v5. Currently packages get put into the same folder as your Node-RED nodes (the userDir folder). This hasn't proven to be the best choice and from v5 they will go into the uibRoot folder (default <userDir>/uibuilder but movable). This will mean moving or reinstalling I'm afraid.

  • In v5, the installed packages list will include more information so that you will be able to see the most likely JavaScript filename you will want to reference. These are still only a guide however because a package may provide several entrypoints.


Perhaps I should also have explained why ../ rather than http:// - this is because using a relative URL like this avoids messing around with specifying protocols and ports and such like. It, for the most part, makes your code a lot simpler and more standard.

1 Like

I still receive:

GET http://xx.xxx.xxx.xxx/:213 GET http://xx.xxx.xxx.xxx:1880/uibuilder/vendor/prism/prism.js net::ERR_ABORTED 404 (Not Found)

using in head

      <link type="text/css" rel="stylesheet" href="../uibuilder/vendor/bootstrap-vue/dist/bootstrap-vue.css" />
      <link href="../uibuilder/vendor/prism/themes/prism.css" rel="stylesheet" />

and in body

<script src="./index.js"></script>

OK, that's because on npmjs.org there are two packages called prism. prism and prismjs - it is prismjs that needs to be installed. If you look into the package.json file for that, you get this:

<link href="../uibuilder/vendor/prismjs/themes/prism.css" rel="stylesheet" />

and

<script src="../uibuilder/vendor/prismjs/prism.js"></script>
1 Like

It works now, I see my index.js using Prism.js, but in my html, it does not want to render the Prismjs tokenized xml... like if the dynamically built variable hLastRcvd_payload was well received in the html, but not rendered by Prism... However when I paste directly the tokenized code, as static data in the html, it does render it as highlighted.

hLastRcvd_payload: function() {
            
            var msgRecvd = this.msgRecvd.payload
            
...
                
                return Prism.highlight(msgRecvd, Prism.languages.xml);
                

and

<pre style="overflow-x: auto;white-space: pre-wrap;word-wrap: break-word;" class="language-xml"><code  style="text-align: left" wrap="hard">{{hLastRcvd_payload}}</code></pre>       

I try to force the rendering but I am not successful yet...

Can you share your index.html and index.js and an example msg?

I managed to achieve my goal ! Sorry I cannot share the whole file.

Here is the solution, following this Stackoverflow post: Prism not working inside Vue component

  1. Initializing the code variable - index.js
    I created a dedicated data "code" and initialized it as per the post explanation but using uibuilder sample syntax:
data() { return {
        startMsg    : 'Vue has started, waiting for messages',
        feVersion   : '',
        ...
        code        : 'void main() { } class MyClass',

    }}, // --- End of data --- //
  1. Creating a dedicated computed property as a function - index.js
highlightedCode: function() {
             var msgRecvd = this.msgRecvd.payload
             this.code=msgRecvd;
             return Prism.highlight(this.code, Prism.languages.xml);
}

Sorry, I removed part of my logic here that is not relevant to this post, but as you can see, I receive a message from the flow, which is a response to a request, what I am highlighting is the response here...

Prism.highlight transforms the the code into an html code ready to be rendered to highlight the code.
Sample:

incoming:

<tag_xml attr="a_attr_value">this is a test</tag_xml>

returned by Prism.highlight(this.code, Prism.languages.xml):

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>tag_xml</span> <span class="token attr-name">attr</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>a_attr_value<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>this is a test<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>tag_xml</span><span class="token punctuation">></span></span>

  1. Rendering in the html page - index.html
  • including relevant css links
<link href="../uibuilder/vendor/prismjs/themes/prism.css" rel="stylesheet" />
<link href="../uibuilder/vendor/vue-code-highlight/themes/window.css" rel="stylesheet">
  • Javascript
    <script src="../uibuilder/vendor/prismjs/prism.js"></script>

  • Plain html - this is one of the most important step, adding v-html to force interpreting the new html code coming from Prism.highlight in the Javascript code.

<pre style="overflow-x: auto;white-space: pre-wrap;word-wrap: break-word;" class="language-xml"><code style="text-align: left" wrap="hard" v-html="highlightedCode"></code></pre>

note: I removed all spaces and carriage returns on this line as it had caused involuntary spaces at the beginning of the highlighted code.

It works like a charm! Each time I receive the message, it is transformed into the relevant html code, then rendered by v-html in the page :grinning:

Thanks !

1 Like

Great, glad you got it working and thanks for sharing what you did. Should be helpful to others as well.

Yes, that is an early mistake for many people. If you send HTML to a Vue component, you need to tell Vue that it is HTML - that's a security feature of Vue and most other frameworks.

Yes, <pre> treats everything literally.

1 Like

Interesting point, does it mean that in a div, or a textarea, I would get it directly rendered?

No :slight_smile: It means that HTML ignores extraneous whitespace in any element EXCEPT <pre> (unless you override the whitespace parameter using CSS).

<pre> is HTML not Vue. Vue still needs to be told that some content contains HTML. Otherwise it is hard to protect the page from inserting attacking HTML (such as a rogue iFrame or script tag).

Remember that a standard web page consists of: HTML, CSS and JavaScript (and maybe a few other things like SVG). VueJS adds some additional smarts via JavaScript to make dynamic interfaces easier to code.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.