fix(desktop): resolve packaged sqlite binding

This commit is contained in:
digua committed 2026-07-10 20:25:53 +08:00
1 parent 39530e2f76
commit 6283281bd8
2 files changed
+61 -6

No files matched your search

+36 -1
View File
@@ -2,7 +2,11 @@ import assert from 'node:assert/strict'
import test from 'node:test'
import * as path from 'node:path'
import { findDesktopNativeBinding, resolveDesktopNativeBinding } from './native-sqlite'
import {
findDesktopNativeBinding,
resolveDesktopNativeBinding,
resolveElectronNativeBindingPath,
} from './native-sqlite'
const BINDING = path.join('native', 'better_sqlite3.node')
@@ -35,6 +39,37 @@ test('findDesktopNativeBinding stops at the filesystem root without hanging', ()
assert.ok(calls <= 5)
})
test('resolveElectronNativeBindingPath prefers packaged resources binding', () => {
const resourcesPath = path.join('/package', 'resources')
const packaged = path.join(resourcesPath, BINDING)
const desktopRoot = path.join('/repo', 'apps', 'desktop')
const dev = path.join(desktopRoot, BINDING)
const exists = (candidate: string) => candidate === packaged || candidate === dev
assert.equal(
resolveElectronNativeBindingPath({
startDir: path.join(desktopRoot, 'out', 'main'),
resourcesPath,
exists,
}),
packaged
)
})
test('resolveElectronNativeBindingPath falls back to the dev binding', () => {
const desktopRoot = path.join('/repo', 'apps', 'desktop')
const dev = path.join(desktopRoot, BINDING)
assert.equal(
resolveElectronNativeBindingPath({
startDir: path.join(desktopRoot, 'out', 'main'),
resourcesPath: path.join('/Electron.app', 'Contents', 'Resources'),
exists: (candidate) => candidate === dev,
}),
dev
)
})
test('resolveDesktopNativeBinding returns undefined under plain Node', () => {
// 测试始终跑在系统 Node(非 Electron):node_modules 保持 Node ABI,无需注入
assert.equal(process.versions.electron, undefined)
+25 -5
View File
@@ -7,9 +7,9 @@
* copy at apps/desktop/native/better_sqlite3.node (prepared by
* scripts/ensure-native.mjs).
*
* In the packaged app this resolver returns undefined: electron-builder
* (npmRebuild: true) rebuilds the bundled node_modules copy for Electron, so
* the default resolution is already correct there.
* Windows packaged apps ship the desktop-owned binding at
* resources/native/better_sqlite3.node and load it explicitly. Other packaged
* platforms can still fall back to electron-builder's rebuilt node_modules copy.
*
* Worker threads cannot compute this reliably from their own __dirname, so the
* main process resolves once and passes the path through workerData.
@@ -41,12 +41,29 @@ export function findDesktopNativeBinding(
return undefined
}
interface ElectronNativeBindingPathOptions {
startDir: string
resourcesPath: string
exists?: (candidate: string) => boolean
}
/**
* 优先解析成品包 resources/native,其次回退到 dev 工作区 native 目录。
* 这里只选择 nativeBinding 路径,不加载数据库,也不接触用户数据。
*/
export function resolveElectronNativeBindingPath(options: ElectronNativeBindingPathOptions): string | undefined {
const exists = options.exists ?? fs.existsSync
const packagedCandidate = path.join(options.resourcesPath, NATIVE_RELATIVE_PATH)
if (exists(packagedCandidate)) return packagedCandidate
return findDesktopNativeBinding(options.startDir, exists)
}
let cachedBinding: string | undefined
let resolved = false
/**
* Resolve the Electron-ABI better-sqlite3 binding for the current process.
* Returns undefined under plain Node (tests/tools) and in the packaged app.
* Returns undefined under plain Node (tests/tools).
*/
export function resolveDesktopNativeBinding(): string | undefined {
if (resolved) return cachedBinding
@@ -57,7 +74,10 @@ export function resolveDesktopNativeBinding(): string | undefined {
return cachedBinding
}
cachedBinding = findDesktopNativeBinding(__dirname)
cachedBinding = resolveElectronNativeBindingPath({
startDir: __dirname,
resourcesPath: process.resourcesPath,
})
if (!cachedBinding && !__dirname.includes('app.asar')) {
console.warn(
'[native-sqlite] Electron-ABI better-sqlite3 binding not found; ' +