Use a js file in NodeJs and VueJs

Hi folks,

I have a js file containing a series of functions. I want to call those functions both in my ui node backend js file, and also in my ui node frontend vue file.

The js file is included in the frontend umd file luckily, so I have it available in the backend and the frontend. However my node's NodeJs backend js file only seems to allow a commonjs module to be loaded via require, while my node's frontend vue file only seems to allow an es6 module to be loaded via import.

I experimented a lot to find a solution. And ChatGpt gave me a lot of of realistic looking examples, but they all failed unfortunately...

Does anybody whether this is possible?
And if yes: how :yum:

Thanks!!
Bart

Not sure if I've fully understood. However, what I do is to build both an CommonJS and an ESM version using ESBUILD.

Hi Julian,
Thanks for joining!
Hmm I thought that I had to make my js file (containing a series of functions) to support both CommonJs (for my node backend) and ESM (for my vue frontend).

But you make me thinking I am talking nonsense. I see here that Vite build (which we execute via npm run build in the D2 dashboard) should convert automatically CommonJs modules to ESM modules.

Will do some more tests this weekend into that direction, and report my feedback here.

1 Like

No problem. :slight_smile:

I was pleasantly surprised recently to stumble upon a Node.js developer who has FINALLY grasped the nettle that is being able to require ESM modules in CommonJS ones. Something that is really starting to hurt Node.js now. Still early days so it will be a few years yet before it becomes mainstream probably but long overdue.

1 Like

Ok I finally found a way to use a js file both in the backend and frontend of a ui node. Not sure whether it is the best way to achieve it, but at least it seems to work. Will describe how to do it, in case anybody else ever needs it.

  1. For the ui-svg node in D2, I created following directory structure:

    node-red-dashboard-2-ui-svg
       nodes
          ui-svg.html
          ui-svg.js
       ui
          components
             UISvg.vue
          svg_utils.js
       vite.config.js
    
  2. The svg_utils.js is a commonJs file, containing the functions that I need in the backend and frontend:

    function addElement(document, svgElement, payload) {
     ...
    }
    function getSvg(svgElement, payload) {
       ...
    }
    function replaceSvg(svgElement, payload) {
     ...
    }
    
    module.exports = {
       addElement,
       getSvg,
       replaceSvg
    }
    
  3. This js file can be used in the backend ui-svg.js just like that:

    module.exports = function (RED) {
       const svgUtils = require('../ui/svg_utils.js')
       ....
       svgUtils.addElement(...)
    }
    

    As you can see in the debugger, all functions are available:

    image

  4. By default Vite will - during the build - only add npm packages (from the node_modules folder) into the bundle (.umd file), which you use in the vue file. So we need to specify in vite.config.js that our js file also needs to be transpiled from commonJs to an ESM module, and that this ESM module code needs to be included into the bundle file:

    import { resolve } from 'path'
    ....
    export default defineConfig({
        ...
        optimizeDeps: {
            include: ['ui/svg_utils.js']
        },
        build: {
            commonjsOptions: {
                 include: [/ui/, /node_modules/],
             },
            ...
         }
    })
    
  5. Now execute npm run build which will build everything and create our .umd bundle file.

  6. Finally use this transpiled ESM module from our sgv_utils.js file into our UISvg.vue file (i.e. the frontend code of the ui node):

    <template>...</template>
    
    <script>
       import * as svg_utils from '../svg_utils.js'
    
       export default {
          ...
         mounted () {
            this.$socket.on('msg-input:' + this.id, (msg) => {
               ...
               svg_utils.addElement(document, svg_drawing, payloadItem)
               ...
            }
         }
       }
    </script>
    

    And now in the debugger you can see that the same js file is available (in the bundle umd file) as an ESM module:

    image

So now - beside all imported npm modules - our custom js file is now also converted by Vite to an ESM module and included in the bundle.

Good luck coding UI nodes for D2!!
Bart

1 Like

BTW step 6 needs to be done before step 5, because you want Vite to put this updated code from your Vue file into the bundle...