fix: 修复打包后模块无法加载的问题,改用静态模块加载

This commit is contained in:
2026-03-11 01:32:06 +08:00
parent 1fa17f7c9d
commit bbd33339a5
4 changed files with 63 additions and 54 deletions

View File

@@ -1,51 +1,59 @@
import { readdirSync, statSync } from 'fs'
import { join, dirname } from 'path'
import { fileURLToPath } from 'url'
import type { ApiModule } from '../infra/types.js' import type { ApiModule } from '../infra/types.js'
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
const moduleFactoryPattern = /^create\w+Module$/
async function discoverModules(): Promise<ApiModule[]> { async function discoverModules(): Promise<ApiModule[]> {
return await getStaticModules()
}
async function getStaticModules(): Promise<ApiModule[]> {
const modules: ApiModule[] = [] const modules: ApiModule[] = []
const entries = readdirSync(__dirname)
for (const entry of entries) { try {
const entryPath = join(__dirname, entry) const { createTodoModule } = await import('./todo/index.js')
modules.push(createTodoModule())
} catch (e) {
console.warn('[ModuleLoader] Failed to load todo module:', e)
}
try { try {
const stats = statSync(entryPath) const { createTimeTrackingModule } = await import('./time-tracking/index.js')
if (!stats.isDirectory()) { modules.push(createTimeTrackingModule())
continue } catch (e) {
} console.warn('[ModuleLoader] Failed to load time-tracking module:', e)
}
const moduleIndexPath = join(entryPath, 'index.ts') try {
let moduleIndexStats: ReturnType<typeof statSync> const { createRecycleBinModule } = await import('./recycle-bin/index.js')
try { modules.push(createRecycleBinModule())
moduleIndexStats = statSync(moduleIndexPath) } catch (e) {
} catch { console.warn('[ModuleLoader] Failed to load recycle-bin module:', e)
continue }
}
if (!moduleIndexStats.isFile()) {
continue
}
const moduleExports = await import(`./${entry}/index.js`) try {
const { createPyDemosModule } = await import('./pydemos/index.js')
modules.push(createPyDemosModule())
} catch (e) {
console.warn('[ModuleLoader] Failed to load pydemos module:', e)
}
for (const exportName of Object.keys(moduleExports)) { try {
if (moduleFactoryPattern.test(exportName)) { const { createDocumentParserModule } = await import('./document-parser/index.js')
const factory = moduleExports[exportName] modules.push(createDocumentParserModule())
if (typeof factory === 'function') { } catch (e) {
const module = factory() as ApiModule console.warn('[ModuleLoader] Failed to load document-parser module:', e)
modules.push(module) }
}
} try {
} const { createAiModule } = await import('./ai/index.js')
} catch (error) { modules.push(createAiModule())
console.warn(`[ModuleLoader] Failed to load module '${entry}':`, error) } catch (e) {
} console.warn('[ModuleLoader] Failed to load ai module:', e)
}
try {
const { createRemoteModule } = await import('./remote/index.js')
modules.push(createRemoteModule())
} catch (e) {
console.warn('[ModuleLoader] Failed to load remote module:', e)
} }
modules.sort((a, b) => { modules.sort((a, b) => {

View File

@@ -1,6 +1,6 @@
import chokidar, { FSWatcher } from 'chokidar'; import chokidar, { FSWatcher } from 'chokidar';
import path from 'path'; import path from 'path';
import { NOTEBOOK_ROOT } from '../config/paths.js'; import { config } from '../config/index.js';
import { eventBus } from '../events/eventBus.js'; import { eventBus } from '../events/eventBus.js';
import { logger } from '../utils/logger.js'; import { logger } from '../utils/logger.js';
import { toPosixPath } from '../../shared/utils/path.js'; import { toPosixPath } from '../../shared/utils/path.js';
@@ -10,16 +10,17 @@ let watcher: FSWatcher | null = null;
export const startWatcher = (): void => { export const startWatcher = (): void => {
if (watcher) return; if (watcher) return;
logger.info(`Starting file watcher for: ${NOTEBOOK_ROOT}`); const notebookRoot = config.notebookRoot;
logger.info(`Starting file watcher for: ${notebookRoot}`);
watcher = chokidar.watch(NOTEBOOK_ROOT, { watcher = chokidar.watch(notebookRoot, {
ignored: /(^|[\/\\])\../, ignored: /(^|[\/\\])\../,
persistent: true, persistent: true,
ignoreInitial: true, ignoreInitial: true,
}); });
const broadcast = (event: string, changedPath: string) => { const broadcast = (event: string, changedPath: string) => {
const rel = path.relative(NOTEBOOK_ROOT, changedPath); const rel = path.relative(notebookRoot, changedPath);
if (!rel || rel.startsWith('..') || path.isAbsolute(rel)) return; if (!rel || rel.startsWith('..') || path.isAbsolute(rel)) return;
logger.info(`File event: ${event} - ${rel}`); logger.info(`File event: ${event} - ${rel}`);
eventBus.broadcast({ event, path: toPosixPath(rel) }); eventBus.broadcast({ event, path: toPosixPath(rel) });

View File

@@ -13,16 +13,6 @@ log.initialize();
const __filename = fileURLToPath(import.meta.url); const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename); const __dirname = path.dirname(__filename);
process.env.NOTEBOOK_ROOT = path.join(app.getPath('documents'), 'XCDesktop');
if (!fs.existsSync(process.env.NOTEBOOK_ROOT)) {
try {
fs.mkdirSync(process.env.NOTEBOOK_ROOT, { recursive: true });
} catch (err) {
log.error('Failed to create notebook directory:', err);
}
}
electronState.setDevelopment(!app.isPackaged); electronState.setDevelopment(!app.isPackaged);
let opencodeProcess: ChildProcess | null = null; let opencodeProcess: ChildProcess | null = null;
@@ -443,6 +433,16 @@ async function startServer() {
} }
app.whenReady().then(async () => { app.whenReady().then(async () => {
process.env.NOTEBOOK_ROOT = path.join(app.getPath('documents'), 'XCDesktop');
if (!fs.existsSync(process.env.NOTEBOOK_ROOT)) {
try {
fs.mkdirSync(process.env.NOTEBOOK_ROOT, { recursive: true });
} catch (err) {
log.error('Failed to create notebook directory:', err);
}
}
await startServer(); await startServer();
await createWindow(); await createWindow();

View File

@@ -35,7 +35,7 @@
"watch:electron": "tsup --config tsup.electron.ts --watch", "watch:electron": "tsup --config tsup.electron.ts --watch",
"electron:dev": "concurrently -k \"npm run server:dev\" \"npm run client:dev\" \"wait-on tcp:3001 tcp:5173 && npm run watch:electron\"", "electron:dev": "concurrently -k \"npm run server:dev\" \"npm run client:dev\" \"wait-on tcp:3001 tcp:5173 && npm run watch:electron\"",
"build:electron": "tsup --config tsup.electron.ts", "build:electron": "tsup --config tsup.electron.ts",
"build:api": "tsup electron/server.ts --format esm --out-dir dist-api --clean --no-splitting --target esnext", "build:api": "tsup electron/server.ts --format esm --out-dir dist-api --clean --target esnext --external electron",
"electron:build": "npm run build && npm run build:electron && npm run build:api && electron-builder" "electron:build": "npm run build && npm run build:electron && npm run build:api && electron-builder"
}, },
"dependencies": { "dependencies": {