Search code examples
javascripttensorflowgoogle-chrome-extension

Error when importing '@tensorflow/tfjs' to use local model in Chrome extension


I tried to use tensorflow local model in my chrome extension. In contentScript:

import * as tf from '@tensorflow/tfjs';
const MODEL_URL = './model/model.json';
const model = tf.load_model(MODEL_URL);
model.run("text");

My manifest.json:

  "content_security_policy": {
    "extension_pages": "script-src 'self' http://localhost; object-src 'self';"
  },
  "background": {
    "service_worker": "background.js"
  },
  "action": {
    "default_title": "My extension",
    "default_popup": "popup.html"
  },
  "permissions": [
    "tabs", 
    "history", 
    "background", 
    "webNavigation", 
    "activeTab", 
    "storage"
  ],
  "content_scripts": [
    {
      "matches": [
        "<all_urls>"
      ],
      "run_at": "document_start",
      "js": [
        "contentScript.js"
      ]
    }
  ]

But I got error Uncaught EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self'".

My package.json:

{
  "name": "my-extension",
  "version": "0.1.0",
  "description": "My Chrome Extension",
  "private": true,
  "scripts": {
    "watch": "webpack --mode=development --watch --config config/webpack.config.js",
    "build": "webpack --mode=production --config config/webpack.config.js"
  },
  "devDependencies": {
    "copy-webpack-plugin": "^6.4.1",
    "css-loader": "^4.3.0",
    "file-loader": "^6.2.0",
    "mini-css-extract-plugin": "^0.10.1",
    "size-plugin": "^2.0.2",
    "webpack": "^4.46.0",
    "webpack-cli": "^3.3.12",
    "webpack-merge": "^5.8.0"
  },
  "dependencies": {
    "@tensorflow/tfjs": "^3.16.0",
    "@tensorflow/tfjs-node": "^3.16.0"
  }
}

What should be the proper way to using local model?


Solution

  • TL;DR -

    Manifest version 3 doesn't allow the use of 'unsafe-eval'. You need to bundle the library code in your extension or use an external API that your extension will call on using something like message-passing.

    Slightly more verbose with links -

    From the official overview for manifest version 3 -

    A key security improvement in Manifest V3 is that extensions can't load remote code like JavaScript or Wasm files. This lets us more reliably and efficiently review the safe behavior of extensions when they're submitted to the Chrome Web Store. Specifically, all logic must be included in the extension's package.

    Instead of remote code, we recommend the use of remote configuration files. See the migration guide for more about how to work with this change.

    Here's the link to the migration guide section on remotely hosted code (PS - Not pasting the entire thing here because these guides could get updated)