feat: auto npm install in dev mode to sync dependencies (#94)
This commit is contained in:
@@ -559,6 +559,31 @@ async def game_loop():
|
||||
print(f"Game loop error: {e}")
|
||||
get_logger().logger.error(f"Game loop error: {e}", exc_info=True)
|
||||
|
||||
|
||||
def ensure_npm_dependencies(web_dir: str) -> bool:
|
||||
"""
|
||||
确保 npm 依赖是最新的。
|
||||
|
||||
Args:
|
||||
web_dir: web 目录路径。
|
||||
|
||||
Returns:
|
||||
True 如果安装成功,False 如果失败。
|
||||
"""
|
||||
import platform
|
||||
print("📦 正在检查前端依赖...")
|
||||
try:
|
||||
if platform.system() == "Windows":
|
||||
subprocess.run("npm install", cwd=web_dir, shell=True, check=True)
|
||||
else:
|
||||
subprocess.run(["npm", "install"], cwd=web_dir, shell=False, check=True)
|
||||
print("✅ 前端依赖已就绪")
|
||||
return True
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"⚠️ npm install 失败: {e},继续启动...")
|
||||
return False
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
# 初始化语言设置
|
||||
@@ -603,6 +628,9 @@ async def lifespan(app: FastAPI):
|
||||
project_root = os.path.abspath(os.path.join(current_dir, '..', '..'))
|
||||
web_dir = os.path.join(project_root, 'web')
|
||||
|
||||
# 确保 npm 依赖是最新的(npm install 会自动跳过已安装的包,通常 <1s)。
|
||||
ensure_npm_dependencies(web_dir)
|
||||
|
||||
print(f"正在启动前端开发服务 (npm run dev) 于: {web_dir}")
|
||||
# 跨平台兼容:Windows 用 shell=True + 字符串,macOS/Linux 用 shell=False + 列表。
|
||||
try:
|
||||
|
||||
76
tests/test_dev_mode.py
Normal file
76
tests/test_dev_mode.py
Normal file
@@ -0,0 +1,76 @@
|
||||
"""Tests for dev mode functionality in the server."""
|
||||
|
||||
import subprocess
|
||||
from unittest.mock import patch, MagicMock
|
||||
import pytest
|
||||
|
||||
|
||||
class TestEnsureNpmDependencies:
|
||||
"""Tests for ensure_npm_dependencies function."""
|
||||
|
||||
def test_npm_install_success_unix(self):
|
||||
"""Test npm install succeeds on Unix-like systems."""
|
||||
from src.server.main import ensure_npm_dependencies
|
||||
|
||||
with patch("platform.system", return_value="Darwin"), \
|
||||
patch("subprocess.run") as mock_run:
|
||||
mock_run.return_value = MagicMock(returncode=0)
|
||||
|
||||
result = ensure_npm_dependencies("/fake/web/dir")
|
||||
|
||||
assert result is True
|
||||
mock_run.assert_called_once_with(
|
||||
["npm", "install"],
|
||||
cwd="/fake/web/dir",
|
||||
shell=False,
|
||||
check=True
|
||||
)
|
||||
|
||||
def test_npm_install_success_windows(self):
|
||||
"""Test npm install succeeds on Windows."""
|
||||
from src.server.main import ensure_npm_dependencies
|
||||
|
||||
with patch("platform.system", return_value="Windows"), \
|
||||
patch("subprocess.run") as mock_run:
|
||||
mock_run.return_value = MagicMock(returncode=0)
|
||||
|
||||
result = ensure_npm_dependencies("/fake/web/dir")
|
||||
|
||||
assert result is True
|
||||
mock_run.assert_called_once_with(
|
||||
"npm install",
|
||||
cwd="/fake/web/dir",
|
||||
shell=True,
|
||||
check=True
|
||||
)
|
||||
|
||||
def test_npm_install_failure_returns_false(self):
|
||||
"""Test npm install failure returns False but doesn't raise."""
|
||||
from src.server.main import ensure_npm_dependencies
|
||||
|
||||
with patch("platform.system", return_value="Darwin"), \
|
||||
patch("subprocess.run") as mock_run:
|
||||
mock_run.side_effect = subprocess.CalledProcessError(1, "npm install")
|
||||
|
||||
result = ensure_npm_dependencies("/fake/web/dir")
|
||||
|
||||
assert result is False
|
||||
|
||||
def test_npm_install_linux(self):
|
||||
"""Test npm install on Linux uses same path as macOS."""
|
||||
from src.server.main import ensure_npm_dependencies
|
||||
|
||||
with patch("platform.system", return_value="Linux"), \
|
||||
patch("subprocess.run") as mock_run:
|
||||
mock_run.return_value = MagicMock(returncode=0)
|
||||
|
||||
result = ensure_npm_dependencies("/fake/web/dir")
|
||||
|
||||
assert result is True
|
||||
# Linux should use the same non-shell approach as macOS.
|
||||
mock_run.assert_called_once_with(
|
||||
["npm", "install"],
|
||||
cwd="/fake/web/dir",
|
||||
shell=False,
|
||||
check=True
|
||||
)
|
||||
Reference in New Issue
Block a user