Skip to content

Commit deac2dd

Browse files
大幅优化启动性能,热启动加速16x,冷启动加速8x。 (#343)
* feat(backend): 增强后端健康检查功能 - `frontend/src/main/backend.ts`: 添加健康检查选项,优化健康检查逻辑 - `frontend/src/main/index.ts`: 移除不必要的后端启动检查 - `frontend/externals/python/window_capture/requirements.txt`: 修复依赖项格式 * perf(startup): switch backend packaging from onefile to onedir to reduce startup latency Goal: eliminate PyInstaller onefile extraction overhead during app startup and improve perceived launch speed. Changes: - /Users/zhuyizhou/MineContext/opencontext.spec: use EXE(exclude_binaries=True) + COLLECT to output onedir backend runtime. - /Users/zhuyizhou/MineContext/frontend/scripts/copy-prebuilt-backend.js: copy full /dist/main onedir runtime into frontend/backend. - /Users/zhuyizhou/MineContext/frontend/electron-builder.yml: include all backend runtime files (not only main/config) in extraResources. - /Users/zhuyizhou/MineContext/build.sh and /Users/zhuyizhou/MineContext/build.bat: verify onedir output path and update run hints. Performance impact (based on 20s progress baseline): - Cold start now reaches app at ~13% => ~2.6s (from 20s), about 87% reduction (~7.7x faster). - Second start now reaches app at ~6% => ~1.2s (from 20s), about 94% reduction (~16.7x faster).
1 parent f758087 commit deac2dd

8 files changed

Lines changed: 199 additions & 101 deletions

File tree

build.bat

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,14 @@ if errorlevel 1 (
8888
REM 6. Verify build and package
8989
echo --^> Verifying build output...
9090
set EXECUTABLE_NAME=main
91-
if exist "dist\%EXECUTABLE_NAME%.exe" (
91+
set ONEDIR_EXE=dist\%EXECUTABLE_NAME%\%EXECUTABLE_NAME%.exe
92+
set BUILT_EXECUTABLE=
93+
94+
if exist "%ONEDIR_EXE%" (
95+
set BUILT_EXECUTABLE=%ONEDIR_EXE%
96+
)
97+
98+
if not "!BUILT_EXECUTABLE!"=="" (
9299
echo Build successful!
93100
echo.
94101

@@ -110,7 +117,11 @@ if exist "dist\%EXECUTABLE_NAME%.exe" (
110117
echo Build complete!
111118
echo.
112119
echo To run:
113-
echo cd dist ^&^& main.exe start
120+
if exist "%ONEDIR_EXE%" (
121+
echo cd dist\main ^&^& main.exe start
122+
) else (
123+
echo cd dist ^&^& main.exe start
124+
)
114125
echo.
115126
echo Options: --port 9000 ^| --host 0.0.0.0 ^| --config config\config.yaml
116127
echo.

build.sh

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,24 @@ fi
5454
# 6. Verify build and package
5555
echo "--> Verifying build output..."
5656
EXECUTABLE_NAME="main" # As defined in the original script
57-
if [ -f "dist/$EXECUTABLE_NAME" ] || [ -f "dist/$EXECUTABLE_NAME.exe" ]; then
57+
ONEDIR_EXECUTABLE="dist/$EXECUTABLE_NAME/$EXECUTABLE_NAME"
58+
ONEDIR_EXECUTABLE_WIN="dist/$EXECUTABLE_NAME/$EXECUTABLE_NAME.exe"
59+
60+
if [ -f "$ONEDIR_EXECUTABLE" ]; then
61+
BUILT_EXECUTABLE="$ONEDIR_EXECUTABLE"
62+
elif [ -f "$ONEDIR_EXECUTABLE_WIN" ]; then
63+
BUILT_EXECUTABLE="$ONEDIR_EXECUTABLE_WIN"
64+
else
65+
BUILT_EXECUTABLE=""
66+
fi
67+
68+
if [ -n "$BUILT_EXECUTABLE" ]; then
5869
echo "✅ Build successful!"
5970

6071
# Ad-hoc sign for macOS to avoid Gatekeeper issues
61-
if [[ "$OSTYPE" == "darwin"* ]] && [ -f "dist/$EXECUTABLE_NAME" ]; then
72+
if [[ "$OSTYPE" == "darwin"* ]] && [ -f "$BUILT_EXECUTABLE" ]; then
6273
echo "--> Performing ad-hoc sign for macOS executable..."
63-
codesign -s - --force --all-architectures --timestamp=none --deep "dist/$EXECUTABLE_NAME" 2>/dev/null || {
74+
codesign -s - --force --all-architectures --timestamp=none --deep "$BUILT_EXECUTABLE" 2>/dev/null || {
6475
echo "⚠️ Warning: Ad-hoc signing failed. The app might still run, but you may see security warnings."
6576
}
6677
fi
@@ -81,11 +92,15 @@ if [ -f "dist/$EXECUTABLE_NAME" ] || [ -f "dist/$EXECUTABLE_NAME.exe" ]; then
8192
echo "✅ Build complete!"
8293
echo
8394
echo "To run:"
84-
echo " cd dist && ./main start"
95+
if [ -f "$ONEDIR_EXECUTABLE" ]; then
96+
echo " cd dist/main && ./main start"
97+
else
98+
echo " cd dist/main && main.exe start"
99+
fi
85100
echo
86101
echo "Options: --port 9000 | --host 0.0.0.0 | --config config/config.yaml"
87102
echo
88103
else
89104
echo "❌ Build failed. Check the PyInstaller logs above for errors."
90105
exit 1
91-
fi
106+
fi

frontend/electron-builder.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ extraResources:
1515
- from: backend/
1616
to: backend/
1717
filter:
18-
- 'main*'
19-
- 'config/**/*'
18+
- '**/*'
2019
asarUnpack:
2120
- resources/**
2221
win:
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
pyobjc-core>=10.0
22
pyobjc-framework-Cocoa>=10.0
3-
pyobjc>=10.0
43
pyobjc-framework-Quartz>=10.0
54
pyobjc-framework-CoreServices>=10.0
65
pyobjc-framework-LaunchServices>=10.0
7-
pyobjc-framework-ApplicationServices>=10.0
6+
pyobjc-framework-ApplicationServices>=10.0

frontend/scripts/copy-prebuilt-backend.js

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ console.log('📦 Copying pre-built backend executable...')
1010
const backendDir = path.join(__dirname, '..', 'backend')
1111
const sourceDir = path.join(__dirname, '..', '..')
1212
const executableName = process.platform === 'win32' ? 'main.exe' : 'main'
13-
const sourceExecutablePath = path.join(sourceDir, 'dist', executableName)
13+
const sourceDistDir = path.join(sourceDir, 'dist')
14+
const sourceOnedirPath = path.join(sourceDistDir, 'main')
15+
const sourceOnedirExecutablePath = path.join(sourceOnedirPath, executableName)
1416
const destExecutablePath = path.join(backendDir, executableName)
1517

1618
// Clean up existing backend directory
@@ -22,9 +24,8 @@ if (fs.existsSync(backendDir)) {
2224
// Ensure backend directory exists
2325
fs.mkdirSync(backendDir, { recursive: true })
2426

25-
// Check if pre-built executable exists
26-
if (!fs.existsSync(sourceExecutablePath)) {
27-
console.error(`❌ Pre-built executable not found at: ${sourceExecutablePath}`)
27+
if (!fs.existsSync(sourceOnedirExecutablePath)) {
28+
console.error(`❌ Pre-built onedir executable not found at: ${sourceOnedirExecutablePath}`)
2829
console.log('')
2930
console.log('🔧 Please build the backend first by running `build.sh` in the project root directory:')
3031
console.log(' cd ../..')
@@ -33,8 +34,18 @@ if (!fs.existsSync(sourceExecutablePath)) {
3334
process.exit(1)
3435
}
3536

36-
// Copy the executable
37-
fs.copyFileSync(sourceExecutablePath, destExecutablePath)
37+
console.log(`📁 Detected onedir backend build at: ${sourceOnedirPath}`)
38+
const entries = fs.readdirSync(sourceOnedirPath)
39+
entries.forEach((entry) => {
40+
const src = path.join(sourceOnedirPath, entry)
41+
const dest = path.join(backendDir, entry)
42+
fs.cpSync(src, dest, { recursive: true, force: true })
43+
})
44+
45+
if (!fs.existsSync(destExecutablePath)) {
46+
console.error(`❌ Backend executable missing after copy: ${destExecutablePath}`)
47+
process.exit(1)
48+
}
3849

3950
// Make executable on Unix systems
4051
if (process.platform !== 'win32') {
@@ -49,7 +60,7 @@ console.log(`✅ Copied executable (${fileSizeInMB} MB)`)
4960

5061
// Copy config files
5162
const configDir = path.join(backendDir, 'config')
52-
const sourceConfigDir = path.join(sourceDir, 'dist', 'config')
63+
const sourceConfigDir = path.join(sourceDistDir, 'config')
5364

5465
if (fs.existsSync(sourceConfigDir)) {
5566
// Create config directory

0 commit comments

Comments
 (0)