mirror of
https://github.com/h-sphere/sql-seal.git
synced 2026-07-22 05:12:18 +00:00
fix: wa-sqlite initialisation fix (#210)
* fix: wa-sqlite initialisation fix * chore: adding changeset * fix: passing wasm between workers to reduce bundle size * fix: fixing issue with vault names
This commit is contained in:
parent
6d4dcc5ece
commit
42a6541650
7 changed files with 32 additions and 57 deletions
5
.changeset/slimy-toys-wear.md
Normal file
5
.changeset/slimy-toys-wear.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
"sqlseal": patch
|
||||
---
|
||||
|
||||
fixing issue with new wa-sqlite on mobile
|
||||
|
|
@ -98,31 +98,8 @@ const workerPlugin = {
|
|||
}));
|
||||
|
||||
build.onLoad({ filter: /.*/, namespace: 'sqlocal-worker-code' }, async () => {
|
||||
// Create a plugin for the worker that resolves virtual imports
|
||||
const workerVirtualPlugin = {
|
||||
name: 'worker-virtual',
|
||||
setup(build) {
|
||||
// Handle virtual WASM URL for wa-sqlite
|
||||
build.onResolve({ filter: /^virtual:wa-sqlite-wasm-url$/ }, args => ({
|
||||
path: args.path,
|
||||
namespace: 'wa-sqlite-wasm-url',
|
||||
}));
|
||||
|
||||
build.onLoad({ filter: /.*/, namespace: 'wa-sqlite-wasm-url' }, async () => {
|
||||
const wasmPath = join(process.cwd(), 'node_modules/wa-sqlite/dist/wa-sqlite-async.wasm');
|
||||
const wasmContents = readFileSync(wasmPath);
|
||||
const wasmBase64 = wasmContents.toString('base64');
|
||||
const wasmDataUrl = `data:application/wasm;base64,${wasmBase64}`;
|
||||
|
||||
return {
|
||||
contents: `export default ${JSON.stringify(wasmDataUrl)};`,
|
||||
loader: 'js',
|
||||
};
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Build sqlocal worker code
|
||||
// WASM binary is NOT embedded in the worker — it's passed from the main thread via Comlink
|
||||
const result = await esbuild.build({
|
||||
entryPoints: ['src/modules/database/sqlocal/sqlocalWorkerDatabase.ts'],
|
||||
bundle: true,
|
||||
|
|
@ -130,7 +107,7 @@ const workerPlugin = {
|
|||
format: 'iife',
|
||||
target: 'es2020',
|
||||
external: ['fs', 'path', 'obsidian'],
|
||||
plugins: [wasmPlugin, workerVirtualPlugin, polyfillNode({
|
||||
plugins: [wasmPlugin, polyfillNode({
|
||||
})],
|
||||
minify: process.argv[2] === 'production',
|
||||
define: {
|
||||
|
|
@ -158,10 +135,13 @@ const workerPlugin = {
|
|||
const wasmPath = join(process.cwd(), 'node_modules/wa-sqlite/dist/wa-sqlite-async.wasm');
|
||||
const wasmContents = readFileSync(wasmPath);
|
||||
const wasmBase64 = wasmContents.toString('base64');
|
||||
const wasmDataUrl = `data:application/wasm;base64,${wasmBase64}`;
|
||||
|
||||
return {
|
||||
contents: `export default ${JSON.stringify(wasmDataUrl)};`,
|
||||
contents: `
|
||||
const wasmBase64 = "${wasmBase64}";
|
||||
const wasmBinary = Uint8Array.from(atob(wasmBase64), c => c.charCodeAt(0));
|
||||
export default wasmBinary;
|
||||
`,
|
||||
loader: 'js',
|
||||
};
|
||||
});
|
||||
|
|
|
|||
|
|
@ -8,8 +8,9 @@ export class DatabaseProvider {
|
|||
constructor(private app: App) { }
|
||||
|
||||
get prefix() {
|
||||
const appId = ((this.app as any).appId ?? '').replace(/[^a-zA-Z0-9_-]/g, '_');
|
||||
const filename = `sqlseal_1__` +
|
||||
sanitise(this.app.vault.getName()) + "___" + (this.app as any).appId;
|
||||
sanitise(this.app.vault.getName()) + "___" + appId;
|
||||
return filename;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ import * as Comlink from 'comlink';
|
|||
import { SqlocalWorkerDatabase } from "./sqlocalWorkerDatabase";
|
||||
import { ColumnDefinition } from "../../../utils/types";
|
||||
import { sanitise } from "../../../utils/sanitiseColumn";
|
||||
// @ts-ignore
|
||||
import wasmBinary from 'virtual:wa-sqlite-wasm-url';
|
||||
|
||||
/**
|
||||
* Main-thread proxy for SqlocalWorkerDatabase.
|
||||
|
|
@ -49,7 +51,7 @@ export class SqlocalDatabaseProxy {
|
|||
|
||||
const instance = await new DatabaseWrap(this.dbName);
|
||||
|
||||
await instance.connect();
|
||||
await instance.connect(wasmBinary);
|
||||
|
||||
this.db = instance;
|
||||
this.isConnected = true;
|
||||
|
|
|
|||
|
|
@ -5,10 +5,6 @@ import { IDBBatchAtomicVFS } from 'wa-sqlite/src/examples/IDBBatchAtomicVFS.js';
|
|||
import { ColumnDefinition } from "../../../utils/types";
|
||||
import { sanitise } from "../../../utils/sanitiseColumn";
|
||||
|
||||
// Get the WASM URL from the virtual module
|
||||
// @ts-ignore
|
||||
import wasmUrl from 'virtual:wa-sqlite-wasm-url';
|
||||
|
||||
/**
|
||||
* Retry an async operation with exponential backoff
|
||||
* @param operation - The async operation to retry
|
||||
|
|
@ -70,6 +66,7 @@ export class SqlocalWorkerDatabase {
|
|||
private isConnected = false;
|
||||
private vfsRegistered = false;
|
||||
private isRecreating = false;
|
||||
private wasmBinary?: Uint8Array;
|
||||
|
||||
constructor(private readonly dbName: string) {
|
||||
}
|
||||
|
|
@ -109,16 +106,12 @@ export class SqlocalWorkerDatabase {
|
|||
return this.sqlite3;
|
||||
}
|
||||
|
||||
if (!this.wasmBinary) {
|
||||
throw new Error('SqlocalWorkerDatabase: wasmBinary not provided. Call connect() with the WASM binary.');
|
||||
}
|
||||
|
||||
try {
|
||||
// Initialize the module with bundled WASM
|
||||
const asyncModule = await SQLiteAsyncESMFactory({
|
||||
locateFile: (file: string) => {
|
||||
if (file.endsWith('.wasm')) {
|
||||
return wasmUrl;
|
||||
}
|
||||
return file;
|
||||
}
|
||||
});
|
||||
const asyncModule = await SQLiteAsyncESMFactory({ wasmBinary: this.wasmBinary, locateFile: (file: string) => file });
|
||||
|
||||
// Use Factory to get the actual sqlite3 API
|
||||
this.sqlite3 = SQLite.Factory(asyncModule);
|
||||
|
|
@ -148,11 +141,13 @@ export class SqlocalWorkerDatabase {
|
|||
}
|
||||
}
|
||||
|
||||
async connect() {
|
||||
async connect(wasmBinary: Uint8Array) {
|
||||
if (this.isConnected) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
this.wasmBinary = wasmBinary;
|
||||
|
||||
try {
|
||||
// Initialize SQLite
|
||||
await this.initializeSQLite();
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
// Mock for virtual:wa-sqlite-wasm-url used in tests
|
||||
// Returns a file:// URL that works with the fetch polyfill in jest.setup.mjs
|
||||
// Returns the WASM binary as Uint8Array (same as production build)
|
||||
|
||||
import { join } from 'path';
|
||||
import { pathToFileURL } from 'url';
|
||||
import { readFileSync } from 'fs';
|
||||
|
||||
const wasmPath = join(process.cwd(), 'node_modules/wa-sqlite/dist/wa-sqlite-async.wasm');
|
||||
const wasmUrl = pathToFileURL(wasmPath).href;
|
||||
const wasmBinary = new Uint8Array(readFileSync(wasmPath));
|
||||
|
||||
export default wasmUrl;
|
||||
export default wasmBinary;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import SQLiteAsyncESMFactory from 'wa-sqlite/dist/wa-sqlite-async.mjs';
|
|||
import * as SQLite from 'wa-sqlite';
|
||||
import { MemoryAsyncVFS } from 'wa-sqlite/src/examples/MemoryAsyncVFS.js';
|
||||
// @ts-ignore - Virtual module from esbuild
|
||||
import wasmUrl from 'virtual:wa-sqlite-wasm-url';
|
||||
import wasmBinary from 'virtual:wa-sqlite-wasm-url';
|
||||
|
||||
type ParamsObject = Record<string, any>;
|
||||
|
||||
|
|
@ -33,15 +33,7 @@ export class WaSqliteMemoryDatabase {
|
|||
throw new Error('Invalid SQLite database file format');
|
||||
}
|
||||
|
||||
// Initialize wa-sqlite
|
||||
const asyncModule = await SQLiteAsyncESMFactory({
|
||||
locateFile: (file: string) => {
|
||||
if (file.endsWith('.wasm')) {
|
||||
return wasmUrl;
|
||||
}
|
||||
return file;
|
||||
}
|
||||
});
|
||||
const asyncModule = await SQLiteAsyncESMFactory({ wasmBinary, locateFile: (file: string) => file });
|
||||
|
||||
this.sqlite3 = SQLite.Factory(asyncModule);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue