Open klehmann opened 2 years ago
Is the idea that the service worker would intercept calls to your server and serve whatever it has locally in the db?
random observation on the particular use case -- I'm not sure sqlite is the best fit for storing images and static files.
Yes, that’s the idea, to have a web application that is synced onto the device/desktop browser and can run offline. When online, app data and HTML/JS is synced with the server.
After trying hard for a few hours, I finally managed to run absurd-sql in a ServiceWorker (for a NextJS app but not important here), here's how I did it:
initBackend
wants a Worker
instance in parameter. In the case of a ServiceWorker
, the Worker
object is navigator.serviceWorker.controller
:if (navigator.serviceWorker.controller) {
const worker = navigator.serviceWorker.controller;
initBackend(worker);
}
fs
, path
, crypto
) (related to issue https://github.com/jlongster/absurd-sql/issues/27):// webpack.config.js
module.exports = {
// ...
resolve: {
fallback: {
crypto: false,
path: false,
fs: false,
}
}
}
public/sql-wasm.wasm
. You then need to tell sql.js where to find it:// in service-worker.js
// ...
// will automatically fetch /sql-wasm.wasm
const SQL = await initSqlJs({ locateFile: () => "/sql-wasm.wasm" });
// ...
postMessage
from the global self
object: it doesn't exist in ServiceWorker global scope, you need to provide it:// in service-worker.js
async function postMessage(message) {
const clients = await self.clients.matchAll({ type: "window" });
for (const client of clients) {
client.postMessage(message);
}
}
// this must be added before calling absurd-sql functions
self.postMessage = postMessage;
activate
lifecycle for example), you can then use it wherever you want:let db;
self.addEventListener("activate", async function (event) {
// ...
db = await initDB();
});
async function initDB() {
const SQL = await initSqlJs({ locateFile: () => "/sql-wasm.wasm" });
const sqlFS = new SQLiteFS(SQL.FS, new IndexedDBBackend());
SQL.register_for_idb(sqlFS);
SQL.FS.mkdir("/sql");
try {
SQL.FS.mount(sqlFS, {}, "/sql");
} catch (e) {
console.error("mount already exists");
}
const path = "/sql/db.sqlite";
if (typeof SharedArrayBuffer === "undefined") {
const stream = SQL.FS.open(path, "a+");
await stream.node.contents.readIfFallback();
SQL.FS.close(stream);
}
const db = new SQL.Database(path, { filename: true });
db.exec(`
PRAGMA page_size=8192;
PRAGMA journal_mode=MEMORY;
`);
return db;
}
Hope this will help some of you. Also, ask me if you want some more details about my NextJS - absurd-sql specific setup.
@mdubourg001 can you share some more details about the next js specific parts of your setup?
Yes, in Next you actually have to update your next.config.js
in order to use the workbox-webpack-plugin
:
npm install workbox-webpack-plugin -D
in next.config.js
:
const { InjectManifest } = require("workbox-webpack-plugin");
module.exports = {
// ...
webpack: (config, options) => {
// ...
if (!options.isServer) {
config.plugins.push(
new InjectManifest({
// update this with the actual location on your serviceWorker source file
swSrc: "./src/service-worker/serviceWorker.ts",
swDest: "../public/sw.js",
include: ["__nothing__"],
})
);
}
// ...
return config;
},
};
And that's it ! 😅 Do you have any specific issue with this in Next @billymoon ?
@mdubourg001 I am getting below error when I run it in service worker
I did some quick tests to run absurd-sql in a serviceworker, but it fails like this:
serviceworker.js:63 Failed to open the database Yb.w.ErrnoError.w.ErrnoError {node: undefined, Oa: 20, message: 'FS error', hd: ƒ}Oa: 20hd: ƒ (c)message: "FS error"node: undefined[[Prototype]]: Error at Object.Yb (webpack://absurd-example-project/./node_modules/@jlongster/sql.js/dist/sql-wasm.js?:160:231) at Object.lc (webpack://absurd-example-project/./node_modules/@jlongster/sql.js/dist/sql-wasm.js?:160:402) at eval (webpack://absurd-example-project/./node_modules/@jlongster/sql.js/dist/sql-wasm.js?:177:15) at new Promise ()
at initSqlJs (webpack://absurd-example-project/./node_modules/@jlongster/sql.js/dist/sql-wasm.js?:24:24)
at openDB (webpack://absurd-example-project/./src/serviceworker.js?:19:77)
at eval (webpack://absurd-example-project/./src/serviceworker.js?:47:20)
eval @ serviceworker.js:63
Before diving deeper I would like to know if this is something that is supposed to work in general. My idea was to serve static HTML/JS files and images out of an absurd-sql instance and add some sync capabilities to fetch them from a server-side Sqlite DB. But there's probably a workaround in using the Worker from the sample project and store duplicates of the web resources in the Cache Storage API.