JS SDK + Vite: Realtime Database not working

I tried to replicate the example app for a movies list in Vite + Vue

The expample code: Real-Time Database Quick Start Guide for JavaScript Developers | Backendless

Copy-pasting the example code and pulling Backendless directly into the HTML file is working as expected and all external updates are reflected in realtime. Nice! :fire:

Now I do the same with Vite + Vue, so i pull in Backendless via npm:

$ npm i backendless

And in my app:

import Backendless from "backendless"
import { ref } from 'vue'

let APP_ID = "my-app-id"
let API_KEY = "my-app-key"

Backendless.initApp(APP_ID, API_KEY)

let moviesStore = Backendless.Data.of("Movies")
let moviesList = ref(null)

moviesStore.find().then(result => {
      moviesList.value = result
      console.log(result)
      enableRealTime()
    })

let enableRealTime = () => {
  let rtHandlers = moviesStore.rt()

  rtHandlers.addUpdateListener(movie => {
    console.log("HANDLING UPDATE")
    moviesList.value = moviesList.value.map(m => m.objectId === movie.objectId ? movie : m)
  })
}

While the find part works fine, it’s having trouble with the realtime handler. No errors are thrown, it is just not listening. It seems like it’s not able to connect to the Websocket server.

Here’s what the network tab looks like for the single HTML file app:

And that’s it.

In the bundled app, however, it looks like this:

And it just keeps polling the /lookup endpoint forever without ever switching to a WS connection.

Setting Backendless.debugMode = true confirms that there seems to be an issue:

Unfortunately the error message is not very verbose so I’m not quite sure what the problem might be. Any help would be appreciated. Thanks!

Hello @quasdunk

Welcome to the Community and thank you for trying Backendless!

I just tested the RT System and it works properly for me, here is my code for testing from the client:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://unpkg.com/backendless@6.2.22/dist/backendless.js"></script>
</head>
<body>
<div id="messages"></div>

<script>
  const APP_ID = ''
  const API_KEY = ''

  const log = (() => {
    const $messages = document.getElementById('messages')

    return (message) => {
      $messages.innerText += `• ${ message }\n`
    }
  })();

  const rtLog = message => log(`---> RT Event <---: ${ message }`)

  const wait = time => new Promise(r => setTimeout(r, time))

  Backendless.initApp(APP_ID, API_KEY)

  log('initialized Backendless JS-SDK')
  
  const personsStore = Backendless.Data.of('Persons')
  const personsRTStore = personsStore.rt()

  personsRTStore.addCreateListener(object => {
    rtLog(`receive a new event from the RT Server about creating a Person object: ${ JSON.stringify(object) }`)
  })

  personsRTStore.addUpdateListener(object => {
    rtLog(`receive a new event from the RT Server about updating a Person object: ${ JSON.stringify(object) }`)
  })

  Backendless.RT.addDisconnectEventListener(() => rtLog('it has been disconnected from the RT Server'))
  Backendless.RT.addReconnectAttemptEventListener(() => rtLog('try to reconnect to the RT Server'))
  Backendless.RT.addConnectErrorEventListener(error => rtLog(`${ error.message }`))

  Backendless.RT.addConnectEventListener(async () => {
    rtLog('it has been connected to the RT Server')
    log('let\'s try to create/update a Person object')

    const newPerson = { name: 'Bob' }

    log(`create a new Person object: ${ JSON.stringify(newPerson) }`)

    const savedPerson = await personsStore.save({ name: 'Bob' })

    log(`created a new Person object: ${ JSON.stringify(savedPerson) }`)

    savedPerson.name = 'Nick'

    log(`update the Person object: ${ JSON.stringify(savedPerson) }`)

    const updatePerson = await personsStore.save(savedPerson)

    log(`updated a new Person object: ${ JSON.stringify(updatePerson) }`)
  })

</script>
</body>
</html>

Just add your APP_ID, API_Key and open it in a web browser

As result, you will see log messages like that:

• initialized Backendless JS-SDK
• ---> RT Event <---: it has been connected to the RT Server
• let's try to create/update a Person object
• create a new Person object: {"name":"Bob"}
• ---> RT Event <---: receive a new event from the RT Server about creating a Person object: {"created":1629198963000,"name":"Bob","___class":"Persons","ownerId":null,"updated":null,"objectId":"60CE33E0-2614-47C8-B124-BB3728F87211"}
• created a new Person object: {"created":1629198963000,"name":"Bob","___class":"Persons","ownerId":null,"updated":null,"objectId":"60CE33E0-2614-47C8-B124-BB3728F87211"}
• update the Person object: {"created":1629198963000,"name":"Nick","___class":"Persons","ownerId":null,"updated":null,"objectId":"60CE33E0-2614-47C8-B124-BB3728F87211"}
• ---> RT Event <---: receive a new event from the RT Server about updating a Person object: {"created":1629198963000,"name":"Nick","___class":"Persons","ownerId":null,"updated":1629198964000,"objectId":"60CE33E0-2614-47C8-B124-BB3728F87211"}
• updated a new Person object: {"created":1629198963000,"name":"Nick","___class":"Persons","ownerId":null,"updated":1629198964000,"objectId":"60CE33E0-2614-47C8-B124-BB3728F87211"}

Regards, Vlad

Hey @vladimir-upirov

Thanks for the reply and the heartly welcome :slight_smile:

As I mentioned, it works fine for me as well if I just pull Backendless into a static HTML file via a CDN like in your example (and the linked example).

But I can’t get it working in a Node app. In my case I’m using Vue + Vite.

Steps to reproduce:

$ npm init vite@latest movies-test -- --template vue
$ cd movies-test
$ npm install
$ npm i backendless

src/App.vue:

<template>
  {{ moviesList }}
</template>

<script setup>
import Backendless from "backendless"
import { ref } from "vue"

Backendless.initApp("app-id", "api-key")

let moviesStore = Backendless.Data.of("Movies")
let moviesList = ref(null)

moviesStore.find().then(result => {
  moviesList.value = result
  enableRealTime()
})

let enableRealTime = () => {
  const rtHandlers = moviesStore.rt()
  rtHandlers.addUpdateListener(movie => {
    moviesList.value = moviesList.value.map(m => m.objectId === movie.objectId ? movie : m)
  })
}
</script>

And finally:

$ npm run dev

I’m not familiar with Vue + Vite, but I remember there was a similar problem with Angular when it transforms the composed code of the 3rd party libs.

Let’s try to debug. You can add the following to see more information in the browser’s log:

Backendless.debugMode=true

Thanks for your patience :slight_smile:

I actually already had the debug output attached to my question, which is this:

Not sure if it helps. Also, I think it’s quite unlikely that the bundler messes it up, because everything else I’ve tried with Backendless seems to be working fine and the pulled in Backendless code is already minified. Might be wrong though.

Regardless: Thanks for looking into it!

oh, sorry, I didn’t notice right away.

Could you please zip a simple project which reproduces the issue and send it us to support@backendless.com

Done :+1:

Thanks again!

got it! thank you, I’m trying to reproduce it

I investigated the problem and unfortunately have no luck!

The only thing I found is that the problem is somewhere with vite module, I would say the root problem is located in rollupjs which is used by the vite module.

Our JS-SDK uses socket.io library for RealTime and I created a simple server and client to check the problem without the JS-SDK.
As the result

  1. it doesn’t work when the lib is imported in the JS code
  2. it works well when it’s imported in the index.html file

Here are those two zip files for testing

client.zip (14.6 KB)
server.zip (970 Bytes)

I do not think we can do something from our side to solve the problem, I would recommend you to create a support topic on the Vite community

@vladimir-upirov Thank you so much for your efforts!!!

This actually helped me out a lot - and I think I was able to fix it!

I didn’t actually expect Vite / Rollup to be the problem, but it looks like it actually is, specifically in combination with socket.io. I’m not remotely smart enough to understand how it all works under the hood, but I think the gist is that Vite only supports ES Modules, and socket.io isn’t one.

But fortunately we can tell Vite how to resolve it by adding this to the vite.config.js:

resolve: {
    alias: {
      "socket.io-client": "socket.io-client/dist/socket.io.js",
    },
  },

And now it works!

I’ve also tested it with Mix / Webpack, and everything seems to work out of the box.

Thanks again for pointing me in the right direction and for taking the time! I really appreciate and you made my day :grinning:

2 Likes

I glad to hear that you solved the problem and shared the solution with our community!
Thank you!