javascriptsqliteweb-worker

problem opening Sqlite3 database from JavaScript Web Worker


I'm trying to insert data from an Sqlite3 database into a web page hosted by a Beaglebone black. Using a JavaScript web worker form an on line example for a number count, the JS worker and HTML page work fine. If I modify the worker code to get the data from a database,and run that in a terminal on the host, that also works fine, the data base is accessed and the data printed out. However, the code will NOT operate as a worker. HTML code (wkr_tst.html)

<!DOCTYPE html>
<html>
<body>

<p>Count numbers: <output id="result"></output></p>
<p>Count numbers: <output id="result2"></output></p>
<button onclick="startWorker()">Start Worker</button>
<button onclick="stopWorker()">Stop Worker</button>

<script>
var w;

function startWorker() {
  if (typeof(Worker) !== "undefined") {
    if (typeof(w) == "undefined") {
      w = new Worker("dbase1.js");
    }
    w.onmessage = function(event) {
      document.getElementById("result").innerHTML = event.data;
      document.getElementById("result2").innerHTML = event.data;
    };
  } else {
    document.getElementById("result").innerHTML = "Sorry! No Web Worker support.";
  }
}

function stopWorker() {
  w.terminate();
  w = undefined;
}
</script>

</body>
</html> 

JavaScript worker:(dbase1.js)

const sqlite3 = require("sqlite3")
var i = 0;
const db = new sqlite3.Database("/home/debian/examples/C_BMS/test2.db",sqlite3.OPEN_READONLY );

function timedCount() {
    i=i+1;
   db.all("SELECT * FROM EpiData", [], (err, rows) => {
        console.log(rows);
    })
postMessage(rows);
//postMessage(i);
//postMessage(i+2);
//setTimeout("timedCount()",500);
}
timedCount(); 
db.close();

With 2 different browsers, using the inspect function, both show that the "require(Sqlite3) function is not defined.

I've tried re-installing both Node.js and the squlite3 extension, with the same result.


Solution

  • Web Workers in JS running in the brower don't have access to require("sqlite3") cuz it is a Nodejs module.

    I suggest you to separate client side (Web Worker) from server side (Nodejs).

    Here is an example of what you can do:

    1. Server side code (Nodejs)

    const express = require('express');
    const cors = require('cors');
    const sqlite3 = require('sqlite3').verbose();
    const app = express();
    
    app.use(cors()); //this enables cors for everyone, first try this and check if your code works
    /*
    do this if you only want specific address to have access to the route
    app.use(cors({
        origin: 'http://192.168.0.52',  //replace with the actual frontend URL
        optionsSuccessStatus: 200
    }));
    */
    const port = 3000; //you can change this port to whatever port you want
    
    const db = new sqlite3.Database('/home/debian/examples/C_BMS/test2.db', sqlite3.OPEN_READONLY);
    
    //make an endpoint to fetch data
    app.get('/data', (req, res) => {
        db.all("SELECT * FROM EpiData", [], (err, rows) => {
            if (err) {
                res.status(500).json({ error: err.message });
                return;
            }
            res.json(rows);
        });
    });
    
    app.listen(port, () => {
        console.log(`Listening on port ${port}`);
    });

    2. Web Worker (dbase1.js)

    function timedCount() {
        fetch('http://<your-server-ip>:3050/data') // changed this line from `fetch("/data")`
            .then(response => response.json())
            .then(data => {
                postMessage(data);  //send data back to the main thread
            })
            .catch(error => {
                console.error(error);
                postMessage('Error fetching data');
            });
    }
    
    timedCount();

    3. wkr_tst.html

    <html>
    <body>
    
    <p>Count numbers: <output id="result"></output></p>
    <p>Count numbers: <output id="result2"></output></p>
    <button onclick="startWorker()">Start Worker</button>
    <button onclick="stopWorker()">Stop Worker</button>
    
    <script>
    var w;
    
    function startWorker() {
      if (typeof(Worker) !== "undefined") {
        if (typeof(w) == "undefined") {
          w = new Worker("dbase1.js");
        }
        w.onmessage = function(event) {
          document.getElementById("result").innerHTML = JSON.stringify(event.data, null, 2);
          document.getElementById("result2").innerHTML = JSON.stringify(event.data, null, 2);
        };
      } else {
        document.getElementById("result").innerHTML = "Sorry! No Web Worker support.";
      }
    }
    
    function stopWorker() {
      w.terminate();
      w = undefined;
    }
    </script>
    
    </body>
    </html>

    Note: Make sure that both your frontend (HTML) and backend (Nodejs) are running on BeagleBone Black and they are served via a web server or nodejs server, and maybe you also have to enable cors (in Nodejs code). Or you can also serve static HTML file with express too.

    app.use(express.static('path to your html file'));

    Hope this helps you.