How do I connect to mongoDB in the background script of a chrome extension?

164 Views Asked by At

Hi I'm new to chrome extension development and I'm currently trying to make one in Mv3 that uses a content script to collect some info from job sites, and sends it to a mongoDB collection through the background script when the extension button is clicked.

The problem I'm having is with the mongoDB connection. Everything starting from collecting the information based on which website the tab is on, to passing it on to the background script when the button is pressed is already working. But I'm getting errors when I try to use mongoDB. The setup code for mongoDB after the import is directly from their documentation.

I was made aware by looking for similar problems here that you cannot import external libraries the regular way in background and content scripts since they have a different context within the browser and after searching for some time I came across this solution/workaround . I attempted to implement the first solution so I added "type":"module" to my declaration of background in manifest. and then I tried importing it in background.js using the regular import statement. Currently I'm getting the error "An unknown error occurred when fetching the script" .

I'm not sure where I'm going wrong and I would appreciate any help on solving this issue. Thank you.

I used "npm init" and "npm install mongodb" within my extension folder to get the required files. Here is the code I have so far: manifest.json:

{
  "manifest_version": 3,
  "name": "Extension",
  "version": "0.1",
  "content_scripts": [
      {
          "matches":[
              "*://www.linkedin.com/jobs/view/*",
              "*://www.monster.com/job-openings/*",
              "*://ca.indeed.com/viewjob*"
          ],
          "js": ["content.js"]
      }
  ],
  "background": {
      "service_worker": "background.js",
      "type": "module"
  },
  "action": {
      "default_icon": "bg.png"
  },
  "permissions": ["scripting", "tabs", "activeTab", "storage"]
}

content.js:


console.log("Chrome extension runnin")

//Properties 
let appSchema = {   // fields
...
}

let temp = appSchema;

let validWebsite = false;

//Triggers
function linkedInTrigger(){   //logic to extract temp info from LinkedIn
...
}
function monsterTrigger(){    //logic to extract temp info from monster
...
}
function indeedTrigger(){     //logic to extract temp info from indeed
...
}
function triggerControl(){    //logic to pick correct trigger
...
}   

if (document.readyState != 'loading') {
    console.log('document is already ready, just execute code here');
    triggerControl();
} else {
    document.addEventListener('DOMContentLoaded', function () {
        console.log('document was not ready, place code here');
        triggerControl();
    });
}

chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) {
    if (request.status === "pressed")
      console.log("received message in content. Message : "+request.status);
      sendResponse(temp);
  }
);

background.js:

console.log("bg script running")


import { MongoClient, ServerApiVersion } from './node_modules/mongodb/mongodb';


const uri = "mongodb+srv://<username>:<password>@cluster1.abc.mongodb.net/?retryWrites=true&w=majority";
// Create a MongoClient with a MongoClientOptions object to set the Stable API version
const client = new MongoClient(uri, {
  serverApi: {
    version: ServerApiVersion.v1,
    strict: true,
    deprecationErrors: true,
  }
});
async function run() {
  try {
    // Connect the client to the server (optional starting in v4.7)
    await client.connect();
    // Send a ping to confirm a successful connection
    await client.db("admin").command({ ping: 1 });
    console.log("Pinged your deployment. You successfully connected to MongoDB!");
  } finally {
    // Ensures that the client will close when you finish/error
    await client.close();
  }
}
run().catch(console.dir);



chrome.action.onClicked.addListener((tab) => {
  
  (async () => {
    const [tab] = await chrome.tabs.query({active: true, lastFocusedWindow: true});
    const response = await chrome.tabs.sendMessage(tab.id, {status: "pressed"});
    console.log("message passed")
    console.log(response)
  })();


});
1

There are 1 best solutions below

1
On

First of all, the node_modules folder is created on your local machine and it is not going to be accessible to people who are going to install and use your plugin. So you need to use tools like Browserify, Webpack or Rollup to generate a bundle.js (file can be named anything) file out of your node_module dependencies. Then import it like this in you background.js

import { MongoClient, ServerApiVersion } from './bundle.js';

Generating bundle.js is one time activity and this bundle.js is going to be shipped with your extension and not node_modules folder.

Secondly, The link you are following seems to be for connection with Mongodb from Node.js, Besides I never seen frontend application (Including extensions) talking to DB directly. This could be harmful as anyone will be able to take over your DB. So ideally you will need a backend layer which exposes an api which will connect to actual DB and make updates to it. Your extension should just call this api with data that needs to be saved to DB.

But I understand that you may not want to write whole backend layer as your use case is simple, So you can use MongoDB's atlas api. This will provide you out of the box api which updates your DB. You will need to just worry about making an api (Provided by Atlas) call on button click from chrome extension and Atlas will take care of updating it in DB. This way your DB won't be exposed and you will have more control over it along with authentication and authorization if needed.