fix(db): preserve native runtime drivers in standalone bundles (#10552)

This commit is contained in:
Jonathan Bailey
2026-08-18 06:52:06 -07:00
committed by GitHub
parent 20af3988cf
commit 0431dd84e7
4 changed files with 51 additions and 10 deletions

View File

@@ -1,4 +1,4 @@
import { createRequire } from "node:module";
import { runtimeRequire as _require } from "./runtimeRequire";
import { existsSync } from "node:fs";
import { createBetterSqliteAdapter } from "./betterSqliteAdapter";
import { createBunSqliteAdapter, type BunSqliteDatabaseLike } from "./bunSqliteAdapter";
@@ -8,7 +8,6 @@ import {
} from "./nodeSqliteShared";
import type { SqliteAdapter } from "./types";
const _require = createRequire(import.meta.url);
type DriverLoader = (moduleName: string) => unknown;

View File

@@ -0,0 +1,36 @@
// src/lib/db/adapters/runtimeRequire.ts
/**
* Load optional database drivers from the runtime rather than bundling them.
*
* The standalone server is emitted as CommonJS chunks and externalizes the
* native database packages. Keep those requests as static `require()` calls so
* webpack preserves the external boundary. Development and tests run as ESM,
* where `require` is unavailable; the `createRequire(import.meta.url)` fallback
* handles those callers.
*/
import { createRequire } from "node:module";
declare const require: NodeRequire | undefined;
function esmRuntimeRequire(specifier: string): unknown {
return createRequire(import.meta.url)(specifier);
}
export function runtimeRequire(specifier: string): unknown {
if (typeof require === "function") {
switch (specifier) {
case "better-sqlite3":
return require("better-sqlite3");
case "node:sqlite":
return require("node:sqlite");
case "bun:sqlite":
return require("bun:sqlite");
case "sql.js":
return require("sql.js");
case "sqlite-vec":
return require("sqlite-vec");
}
}
return esmRuntimeRequire(specifier);
}

View File

@@ -1,21 +1,19 @@
import os from "os";
import path from "path";
import { createRequire } from "node:module";
import { runtimeRequire as _require } from "./adapters/runtimeRequire";
const _require = createRequire(import.meta.url);
function getDatabaseClass() {
type DatabaseConstructor = typeof import("better-sqlite3");
function getDatabaseClass(): DatabaseConstructor | null {
try {
if (process.versions.bun) {
return _require("bun:sqlite").Database;
return (_require("bun:sqlite") as { Database: DatabaseConstructor }).Database;
}
return _require("better-sqlite3");
return _require("better-sqlite3") as DatabaseConstructor;
} catch {
return null;
}
}
const Database = process.versions.bun
? (_require("bun:sqlite").Database as typeof import("better-sqlite3"))
: (_require("better-sqlite3") as typeof import("better-sqlite3"));
function databaseOptions(readonly = false) {
return readonly ? { readonly: true } : { readwrite: true, create: true };

View File

@@ -4,6 +4,9 @@ import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { createRequire } from "node:module";
import type * as NodePath from "node:path";
import { runtimeRequire } from "../../../src/lib/db/adapters/runtimeRequire.ts";
const {
createSyncDriverFactory,
@@ -33,7 +36,12 @@ function createTempDatabasePath(t: TestContext) {
return databasePath;
}
describe("driverFactory", () => {
test("runtimeRequire loads Node built-ins outside webpack", () => {
const nodePath = runtimeRequire("node:path") as typeof NodePath;
assert.equal(nodePath.basename("/tmp/omniroute.sqlite"), "omniroute.sqlite");
});
test("tryOpenSync retorna adapter síncrono ou null", () => {
const adapter = tryOpenSync(":memory:");
if (adapter) {