我正在尝试让持久存储与 WASM SQLite 一起使用。
我在background.js文件中的代码是这样的
const worker = new Worker('./worker.js');
worker.postMessage({ loadSQLite: true });
但它永远不会越过 Worker 部分。我收到以下错误。
Uncaught ReferenceError: Worker is not defined
因此,在做了一些研究之后,我尝试了一些可能的解决方案。有些人说你不能在工人中产生工人,并且有一个子工人解决方案,但这对我不起作用(如果它对你有用,请告诉我,但我无法让它发挥作用)。
我认为worker.js中的代码并不重要,但我会在那里发布我想要做的事情。
worker.js
import sqlite3InitModule from './lib/@sqlite.org/sqlite-wasm/index.mjs';
const log = (...args) => console.log(...args);
const error = (...args) => console.error(...args);
console.log("worker loaded...");
//@JA - SQLite Database Setup
const start = function (sqlite3) {
console.log(sqlite3);
const capi = sqlite3.capi; // C-style API
const oo = sqlite3.oo1; // High-level OO API
console.log(`SQLite3 Version ${capi.sqlite3_libversion()} - ${capi.sqlite3_sourceid()}`);
let db;
if ('OpfsDb' in oo) {
db = new oo.OpfsDb('/mydb.sqlite3');
console.log('The OPFS is available.');
console.log(`Persisted db = ${db.filename}`);
} else {
db = new oo.DB('/mydb.sqlite3', 'ct');
console.log('The OPFS is not available.');
console.log(`transient db = ${db.filename}`);
}
try{
db.exec(`CREATE TABLE IF NOT EXISTS results (id INTEGER PRIMARY KEY AUTOINCREMENT, search_name TEXT, strategy_name TEXT, json_data TEXT)`);
} finally {
db.close();
}
}
self.addEventListener('message', (event) => {
if (event.data.loadSQLite) {
// Load the SQLite library within the web worker
sqlite3InitModule({
print: log,
printErr: error,
}).then(function (sqlite3) {
log('SQLite Done initializing.');
try {
start(sqlite3);
} catch (e) {
error('Exception:', e.message);
}
});
}
});
如果我把它放在worker.js之外,这段代码就可以工作,但是它是暂时的,这意味着数据库不会保存!
我的目标是让它使用 OPFS 进行持久存储,但事实证明这非常困难,我遇到了障碍。如有任何帮助,我们将不胜感激!
我的目标是让它说
The OPFS is available.
来自此资源:https://sqlite.org/wasm/doc/trunk/persistence.md
它说必须是服务人员才能工作。我假设background.js是一个服务工作者,但显然它不是,否则这会在那里工作。这就是为什么我试图在那里创建一个服务工作者。
我的清单文件在这里:
{
"name" : "__MSG_appName__",
"short_name": "__MSG_appShortName__",
"description": "__MSG_appDescription__",
"version" : "2.0.2",
"version_name": "2.0.2",
"manifest_version": 3,
"default_locale": "en",
"minimum_chrome_version": "88",
"permissions": [
"activeTab",
"tabs",
"storage",
"scripting",
"unlimitedStorage",
"declarativeNetRequest",
"declarativeNetRequestFeedback"
],
"icons": {
"16": "./assets/img/icon-16.png",
"32": "./assets/img/icon-32.png",
"48": "./assets/img/icon-48.png",
"128": "./assets/img/icon-128.png"
},
"background":{
"service_worker": "background.js",
"type": "module"
},
"action":{
"default_popup": "./popup.html",
"default_icons": {
"16": "./assets/img/icon-16.png",
"32": "./assets/img/icon-32.png",
"48": "./assets/img/icon-48.png",
"128": "./assets/img/icon-128.png"
},
"default_title": "__MSG_appName__"
},
"host_permissions": [
"https://*.tradingview.com/*"
],
"content_scripts": [
{
"all_frames": true,
"matches": [
"https://*.tradingview.com/*",
"http://*.tradingtools.software/*"
],
"css": [
"./css/trading-view.css",
"./lib/datetimepicker/jquery.datetimepicker.min.css"
],
"js": [
"./lib/jquery/jquery-3.6.0.min.js",
"./lib/lodash/lodash.js",
"./lib/luxon/non-es6-luxon.js",
"./lib/datetimepicker/jquery.datetimepicker.full.min.js",
"./js/classes/scanner.js",
"./js/classes/dialogs.js",
"./js/classes/queues.js",
"./js/helpers/helpers.js",
"./js/helpers/inputs.js",
"./js/helpers/security.js",
"./js/helpers/manipulators.js",
"./js/helpers/strategy.js",
"./js/helpers/license.js",
"./js/globals/globals.js",
"./js/content/tradingview-content-script.js"
],
"run_at": "document_idle"
},
{
"all_frames": true,
"matches":["https://*.tradingview.com/*","http://*.tradingtools.software/*"],
"js":[ "./js/injectors/before.js" ],
"run_at": "document_start"
},
{
"all_frames": true,
"matches":["https://*.tradingview.com/*","http://*.tradingtools.software/*"],
"js":[ "./js/injectors/after.js" ],
"run_at": "document_end"
}
],
"web_accessible_resources": [{
"resources": ["/js/injectors/before_inject.js","/js/injectors/after_inject.js","/js/injectors/page-script.js","/assets/*","workers.js"],
"matches": ["<all_urls>"]
}],
"content_security_policy": {
"extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self'; worker-src 'self'",
"sandbox": "sandbox allow-scripts; default-src 'self' 'wasm-unsafe-eval'; frame-src 'self'; worker-src 'self'"
}
}
您无法从扩展服务工作人员启动工作人员,但您可以在屏幕外文档
中创建一个工作人员至于在 Chrome 扩展中使用 OPFS 运行 SQLite,您可以使用屏幕外文档来执行此操作。这是一个例子。
您还可以克隆此存储库并运行示例 - https://github.com/clmnin/sqlite-opfs-mv3
{
"manifest_version": 3,
"name": "MV3 Sqlite OPFS Example",
"version": "1",
"description": "MV3 Sqlite OPFS Example",
"background": {
"service_worker": "index.js",
"type": "module"
},
"content_security_policy": {
"extension_pages": "script-src 'self' 'wasm-unsafe-eval'"
},
"permissions": [
"offscreen"
]
}
console.log('bg ready');
let creating: Promise<void> | null;
async function setupOffscreenDocument(path: string) {
// Check all windows controlled by the service worker to see if one
// of them is the offscreen document with the given path
if (await chrome.offscreen.hasDocument?.()) return;
// create offscreen document
if (creating) {
await creating;
} else {
creating = chrome.offscreen.createDocument({
url: chrome.runtime.getURL(path),
reasons: [
chrome.offscreen.Reason.WORKERS || chrome.offscreen.Reason.BLOBS,
],
justification: "To run web worker to run sqlite",
});
await creating;
creating = null;
}
}
setupOffscreenDocument("index.html");
<!DOCTYPE html>
<script type="module" src="./index.ts"></script>
const worker = new Worker(
new URL("./worker.js", import.meta.url),
{ type: "module" },
);
worker.onmessage = function ({ data }) {
switch (data.type) {
case 'log':
console.log(`Message: ${data.payload.args}`);
break;
default:
console.log(`ERROR: Unhandled message: ${data.type}`);
}
};
import sqlite3InitModule from '@sqlite.org/sqlite-wasm';
const logHtml = function (cssClass, ...args) {
postMessage({
type: 'log',
payload: { cssClass, args },
});
};
const log = (...args) => logHtml('', ...args);
const error = (...args) => logHtml('error', ...args);
const start = function (sqlite3) {
const capi = sqlite3.capi; // C-style API
const oo = sqlite3.oo1; // High-level OO API
log('SQLite3 version', capi.sqlite3_libversion(), capi.sqlite3_sourceid());
let db;
if ('OpfsDb' in oo) {
db = new oo.OpfsDb('/mydb.sqlite3');
log('The OPFS is available.');
log('Persisted db =', db.filename);
} else {
db = new oo.DB('/mydb.sqlite3', 'ct');
log('The OPFS is not available.');
log('transient db =', db.filename);
}
try {
log('Create a table...');
db.exec('CREATE TABLE IF NOT EXISTS t(a,b)');
log('Insert some data using exec()...');
let i;
for (i = 20; i <= 25; ++i) {
db.exec({
sql: 'INSERT INTO t(a,b) VALUES (?,?)',
bind: [i, i * 2],
});
}
log("Query data with exec() using rowMode 'array'...");
db.exec({
sql: 'SELECT a FROM t ORDER BY a LIMIT 3',
rowMode: 'array', // 'array' (default), 'object', or 'stmt'
callback: function (row) {
log('row ', ++this.counter, '=', row);
}.bind({ counter: 0 }),
});
} finally {
db.close();
}
};
log('Loading and initializing sqlite3 module...');
sqlite3InitModule({
print: log,
printErr: error,
}).then(function (sqlite3) {
log('Done initializing. Running demo...');
try {
start(sqlite3);
} catch (e) {
error('Exception:', e.message);
}
});