#WASM sqlite in cloudflare web workers

1 messages · Page 1 of 1 (latest)

sturdy timber
#

I'm trying to get a WASM version of sqlite running in cloudflare workers (in memory).
Structure, a hybrid app deployed to cloudflare pages. Builds an in memory sqlite database and serves its contents via an API.

Side Note: This is probably somewhat foolish, but I've gone down the rabbit hole

Using this wasm vita plugin code seems promising. It should allow importing wasm in cloudflare, however I'm running into a blow up with the cloudflare build

Note I've forked sql.js because the default emscripten builds blow up in cloudflare workers when trying to read various globals that don't actually exist. Adding an emscripten build argument of -s ENVIRONMENT='web' fixes this. This is tested and working with a vanilla cloudflare worker, but I'm unable to get vite to bundle it correctly

✘ [ERROR] Could not resolve "./../../_astro/sql-wasm.18fc45ef.wasm"
    ../../../dist/sites/acme/anvils/$server_build/chunks/pages/db_37f9fabe.mjs:1:7:
      1 │ import './../../_astro/sql-wasm.18fc45ef.wasm';
        ╵        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 error   Could not resolve "./../../_astro/sql-wasm.18fc45ef.wasm"
  File:
    ../../../dist/sites/acme/anvils/$server_build/chunks/pages/db_37f9fabe.mjs:1:7

It seems like something is going wrong in the cloudflare adapter so that the path is not handling this temporary $server_build directory, or perhaps not moving the wasm file into the $server_build directory? I'm not seeing anything obvious looking at the @astro/cloudflare adapter code

  1. Any immediate ideas anyone has on what's going wrong in the cloudflare adapter?
  2. Any better ideas for running sqlite in the cloudflare worker? (Avoiding D1 since its alpha. Database will be pretty small)
GitHub

Vite plugin to to import wasm files to cloudflare workers - GitHub - hadeeb/vite-plugin-wasm: Vite plugin to to import wasm files to cloudflare workers

GitHub

The all-in-one web framework designed for speed. ⭐️ Star to support our work! - withastro/astro

#

Astro config looks something like this:

import { defineConfig } from 'astro/config';
import cloudflare from '@astrojs/cloudflare';
import { wasmEdgeModule } from './wasm-plugin';

// https://astro.build/config
export default defineConfig({
  outDir: '../../../dist/sites/acme/anvils',
  output: 'hybrid',
  adapter: cloudflare({}),
  vite: {
    build: {
      // temp. For better cloudflare stack traces
      minify: false,
    },
    plugins: [wasmEdgeModule({ target: 'cloudflare' })],
  },
});

#

worker endpoint looks like this:

import { APIContext, EndpointOutput } from 'astro';
// @ts-ignore
import initSqlJs from 'cloudflare-worker-sqlite-wasm';
// @ts-ignore
import worker from 'cloudflare-worker-sqlite-wasm/dist/sql-wasm.wasm?module';

export const prerender = false;

function instantiateWorker(
  importObject: WebAssembly.Imports
): WebAssembly.Instance {
  return new WebAssembly.Instance(worker, importObject);
}

export async function GET(
  context: APIContext
): Promise<EndpointOutput | Response> {
  const SQL: any = await new Promise((onSuccess, onFail) => {
    initSqlJs({
      instantiateWasm(info: any, receive: any) {
        try {
          const worker = instantiateWorker(info);
          receive(worker);
          return worker.exports;
        } catch (ex) {
          console.error('failed to instantiate', ex);
          onFail(ex);
          return false;
        }
      },
      log: console.log,
      error: console.error,
    }).then((builder: any) => onSuccess(builder));
  });

  const db = new SQL.Database();
  let sqlstr =
    "CREATE TABLE hello (a int, b char); \
  INSERT INTO hello VALUES (0, 'hello'); \
  INSERT INTO hello VALUES (1, 'world');";
  db.run(sqlstr); // Run the query without returning anything

  const stmt = db.prepare('SELECT * FROM hello WHERE a=:aval AND b=:bval');

  // Bind values to the parameters and fetch the results of the query
  const result = stmt.getAsObject({ ':aval': 1, ':bval': 'world' });
  console.log(result); // Will print {a:1, b:'world'}

  return new Response(JSON.stringify(result), {
    status: 418,
    headers: {
      'Content-Type': 'application/json',
    },
  });
}