mirror of
https://github.com/hellodigua/ChatLab.git
synced 2026-05-28 01:57:25 +08:00
fix: dev native startup issues
This commit is contained in:
@@ -14,6 +14,9 @@ export default defineConfig(() => {
|
||||
},
|
||||
define: {
|
||||
'process.env.APTABASE_APP_KEY': JSON.stringify(process.env.APTABASE_APP_KEY || ''),
|
||||
// ws 的原生加速依赖是可选项;主进程打包时禁用它们,避免 Vite 将缺失的可选依赖改写为启动即抛错。
|
||||
'process.env.WS_NO_BUFFER_UTIL': JSON.stringify('true'),
|
||||
'process.env.WS_NO_UTF_8_VALIDATE': JSON.stringify('true'),
|
||||
},
|
||||
build: {
|
||||
rollupOptions: {
|
||||
|
||||
+3
-2
@@ -29,8 +29,9 @@
|
||||
"build:win": "pnpm run build && electron-builder --win --config electron-builder.yml -p never",
|
||||
"build:linux": "pnpm run build && electron-builder --linux --config electron-builder.yml -p never",
|
||||
"dev:app": "vite --config vite.web.config.mts",
|
||||
"dev:serve": "tsx watch packages/server/src/cli.ts serve",
|
||||
"dev:web": "CHATLAB_AUTO_SERVE=1 vite --config vite.web.config.mts",
|
||||
"ensure:server-native": "pnpm --filter chatlab run ensure-native",
|
||||
"dev:serve": "pnpm run ensure:server-native && tsx watch packages/server/src/cli.ts serve",
|
||||
"dev:web": "pnpm run ensure:server-native && CHATLAB_AUTO_SERVE=1 vite --config vite.web.config.mts",
|
||||
"build:web": "vite build --config vite.web.config.mts",
|
||||
"type-check:web": "vue-tsc --noEmit -p tsconfig.web.json",
|
||||
"type-check:node": "tsc --noEmit -p tsconfig.node.json",
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
"main": "./src/index.ts",
|
||||
"types": "./src/index.ts",
|
||||
"scripts": {
|
||||
"cli": "tsx src/cli.ts",
|
||||
"cli": "node scripts/ensure-native.mjs && tsx src/cli.ts",
|
||||
"ensure-native": "node scripts/ensure-native.mjs",
|
||||
"rebuild-native": "bash scripts/rebuild-native.sh",
|
||||
"rebuild-sqlite": "npm rebuild better-sqlite3"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { existsSync } from 'node:fs'
|
||||
import { dirname, resolve } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { spawnSync } from 'node:child_process'
|
||||
|
||||
const currentFile = fileURLToPath(import.meta.url)
|
||||
const scriptDir = dirname(currentFile)
|
||||
const serverDir = dirname(scriptDir)
|
||||
const nativePath = resolve(serverDir, 'native/better_sqlite3.node')
|
||||
const rebuildScript = resolve(scriptDir, 'rebuild-native.sh')
|
||||
|
||||
export function getNativeStatus(bindingPath, nodeExecutable = process.execPath) {
|
||||
if (!existsSync(bindingPath)) {
|
||||
return { ok: false, reason: 'missing', message: `Native binding not found: ${bindingPath}` }
|
||||
}
|
||||
|
||||
const result = spawnSync(
|
||||
nodeExecutable,
|
||||
['-e', 'require(process.argv[1]); process.stdout.write(process.versions.modules)', bindingPath],
|
||||
{ encoding: 'utf8' }
|
||||
)
|
||||
|
||||
if (result.status === 0) {
|
||||
return { ok: true, reason: 'valid', abi: result.stdout.trim() }
|
||||
}
|
||||
|
||||
return {
|
||||
ok: false,
|
||||
reason: 'invalid',
|
||||
message: (result.stderr || result.stdout || result.error?.message || 'Native binding failed to load').trim(),
|
||||
}
|
||||
}
|
||||
|
||||
function runRebuild() {
|
||||
const result = spawnSync('bash', [rebuildScript], {
|
||||
cwd: serverDir,
|
||||
stdio: 'inherit',
|
||||
})
|
||||
|
||||
if (result.status !== 0) {
|
||||
process.exit(result.status || 1)
|
||||
}
|
||||
}
|
||||
|
||||
function main() {
|
||||
const checkOnly = process.argv.includes('--check')
|
||||
const status = getNativeStatus(nativePath)
|
||||
|
||||
if (status.ok) {
|
||||
console.error(`[server native] better-sqlite3 ready (Node ABI ${status.abi})`)
|
||||
return
|
||||
}
|
||||
|
||||
if (checkOnly) {
|
||||
console.error(`[server native] ${status.message}`)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
console.error(`[server native] ${status.message}`)
|
||||
console.error('[server native] Rebuilding better-sqlite3 for the current system Node.js...')
|
||||
runRebuild()
|
||||
|
||||
const rebuilt = getNativeStatus(nativePath)
|
||||
if (!rebuilt.ok) {
|
||||
console.error(`[server native] Rebuild completed, but native binding is still unusable: ${rebuilt.message}`)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
console.error(`[server native] better-sqlite3 ready (Node ABI ${rebuilt.abi})`)
|
||||
}
|
||||
|
||||
if (process.argv[1] && currentFile === resolve(process.argv[1])) {
|
||||
main()
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { spawnSync } from 'node:child_process'
|
||||
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'
|
||||
import { tmpdir } from 'node:os'
|
||||
import path from 'node:path'
|
||||
import test from 'node:test'
|
||||
|
||||
import { getNativeStatus } from './ensure-native.mjs'
|
||||
|
||||
test('reports missing native binding', () => {
|
||||
const dir = mkdtempSync(path.join(tmpdir(), 'chatlab-native-missing-'))
|
||||
try {
|
||||
const status = getNativeStatus(path.join(dir, 'better_sqlite3.node'))
|
||||
assert.equal(status.ok, false)
|
||||
assert.equal(status.reason, 'missing')
|
||||
} finally {
|
||||
rmSync(dir, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
|
||||
test('reports invalid native binding load failure', () => {
|
||||
const dir = mkdtempSync(path.join(tmpdir(), 'chatlab-native-invalid-'))
|
||||
try {
|
||||
const nativePath = path.join(dir, 'better_sqlite3.node')
|
||||
writeFileSync(nativePath, 'not a native module')
|
||||
|
||||
const status = getNativeStatus(nativePath)
|
||||
assert.equal(status.ok, false)
|
||||
assert.equal(status.reason, 'invalid')
|
||||
assert.match(status.message, /file too short|not a mach-o file|invalid/)
|
||||
} finally {
|
||||
rmSync(dir, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
|
||||
test('reports valid native binding when it can be loaded by current Node', () => {
|
||||
const nativePath = path.resolve('packages/server/native/better_sqlite3.node')
|
||||
const status = getNativeStatus(nativePath)
|
||||
assert.equal(status.ok, true)
|
||||
assert.equal(status.reason, 'valid')
|
||||
})
|
||||
|
||||
test('prints status to stderr so CLI stdout stays machine-readable', () => {
|
||||
const result = spawnSync(process.execPath, ['packages/server/scripts/ensure-native.mjs', '--check'], {
|
||||
encoding: 'utf8',
|
||||
})
|
||||
|
||||
assert.equal(result.status, 0)
|
||||
assert.equal(result.stdout, '')
|
||||
assert.match(result.stderr, /better-sqlite3 ready/)
|
||||
})
|
||||
Reference in New Issue
Block a user