Node 22+ everywhere, LF text on Windows checkouts, CI actions v7
- Node minimum is 22 in package.json engines, the start scripts, the service installer, setup and doctor, matching the README, the release notes and the CI matrix (22 / 24). - .gitattributes: CSS, HTML, JSON, Markdown and YAML check out with LF, so `node --test` on Windows matches the CSS rules the UI tests read; the Windows test step is no longer continue-on-error. - CI: actions/checkout@v7 and actions/setup-node@v7 (Node 24 runtime).
This commit is contained in:
1 parent
b59aa15ee2
commit
bb5c792a4d
12 files changed
+31
-26
No files matched your search
@@ -8,6 +8,13 @@
|
|||||||
*.mjs text eol=lf
|
*.mjs text eol=lf
|
||||||
*.js text eol=lf
|
*.js text eol=lf
|
||||||
*.py text eol=lf
|
*.py text eol=lf
|
||||||
|
# Text the tests read and match line by line (CSS rules, HTML, data, docs): LF everywhere, so a Windows checkout
|
||||||
|
# (core.autocrlf=true) runs `node --test` exactly like Linux and macOS.
|
||||||
|
*.css text eol=lf
|
||||||
|
*.html text eol=lf
|
||||||
|
*.json text eol=lf
|
||||||
|
*.md text eol=lf
|
||||||
|
*.yml text eol=lf
|
||||||
# binary assets
|
# binary assets
|
||||||
*.png binary
|
*.png binary
|
||||||
*.jpg binary
|
*.jpg binary
|
||||||
|
|||||||
@@ -31,9 +31,9 @@ jobs:
|
|||||||
RENDER_E2E: '0'
|
RENDER_E2E: '0'
|
||||||
NO_COLOR: '1'
|
NO_COLOR: '1'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v7
|
||||||
|
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v7
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node }}
|
node-version: ${{ matrix.node }}
|
||||||
cache: npm
|
cache: npm
|
||||||
@@ -46,8 +46,6 @@ jobs:
|
|||||||
|
|
||||||
- name: Unit & integration tests
|
- name: Unit & integration tests
|
||||||
run: node --test
|
run: node --test
|
||||||
# Linux is the reference platform; Windows results are informative until the suite is proven there.
|
|
||||||
continue-on-error: ${{ matrix.os == 'windows-latest' }}
|
|
||||||
|
|
||||||
- name: Server smoke test (boot, /healthz, index.html, doctor)
|
- name: Server smoke test (boot, /healthz, index.html, doctor)
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|||||||
+1
-1
@@ -27,7 +27,7 @@ Out of scope v1: matchmaking queue, training/tutorial, DIY (甄选) slots (the 4
|
|||||||
|
|
||||||
## 1. Tech stack
|
## 1. Tech stack
|
||||||
|
|
||||||
- **Node.js ≥ 18** (tested on 22), ESM (`"type": "module"`), single dependency `ws@8`. No bundler, no TypeScript. JSDoc types where helpful.
|
- **Node.js ≥ 22** (CI: 22 and 24), ESM (`"type": "module"`), single dependency `ws@8`. No bundler, no TypeScript. JSDoc types where helpful.
|
||||||
- **Server-authoritative simulation.** Clients send *intents*; the server validates, mutates state and pushes state/snapshots.
|
- **Server-authoritative simulation.** Clients send *intents*; the server validates, mutates state and pushes state/snapshots.
|
||||||
- **Client:** static files, native ES modules. Vendored libs in `public/vendor/`: `pixi.min.js` (PixiJS **7.4.2** UMD, global `PIXI`), `pixi-spine.js` (**4.0.6** UMD, `PIXI.spine`), `preact.module.js` + `hooks.module.js` + `htm.module.js` (Preact 10 + htm, no build step). No CDN at runtime (LAN play must work offline).
|
- **Client:** static files, native ES modules. Vendored libs in `public/vendor/`: `pixi.min.js` (PixiJS **7.4.2** UMD, global `PIXI`), `pixi-spine.js` (**4.0.6** UMD, `PIXI.spine`), `preact.module.js` + `hooks.module.js` + `htm.module.js` (Preact 10 + htm, no build step). No CDN at runtime (LAN play must work offline).
|
||||||
- **Shared code** in `shared/` is imported by both server and browser (pure ESM, no Node APIs).
|
- **Shared code** in `shared/` is imported by both server and browser (pure ESM, no Node APIs).
|
||||||
|
|||||||
Generated
+1
-1
@@ -21,7 +21,7 @@
|
|||||||
"puppeteer-core": "^23.11.1"
|
"puppeteer-core": "^23.11.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=22"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@pixi-spine/base": {
|
"node_modules/@pixi-spine/base": {
|
||||||
|
|||||||
+1
-1
@@ -35,7 +35,7 @@
|
|||||||
"launch": "node scripts/launch.mjs"
|
"launch": "node scripts/launch.mjs"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=22"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"htm": "^3.1.1",
|
"htm": "^3.1.1",
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ try {
|
|||||||
if (-not $nodeCmd) { throw '未找到 Node.js:请先安装(winget install OpenJS.NodeJS.LTS),然后重新打开 PowerShell。' }
|
if (-not $nodeCmd) { throw '未找到 Node.js:请先安装(winget install OpenJS.NodeJS.LTS),然后重新打开 PowerShell。' }
|
||||||
$nodeExe = $nodeCmd.Source
|
$nodeExe = $nodeCmd.Source
|
||||||
$major = [int](((& $nodeExe -v) -replace '^v', '').Split('.')[0])
|
$major = [int](((& $nodeExe -v) -replace '^v', '').Split('.')[0])
|
||||||
if ($major -lt 18) { throw "Node.js 版本太旧(需要 18+):$(& $nodeExe -v)" }
|
if ($major -lt 22) { throw "Node.js 版本太旧(需要 22+):$(& $nodeExe -v)" }
|
||||||
if ($nodeExe -like "$env:USERPROFILE*") {
|
if ($nodeExe -like "$env:USERPROFILE*") {
|
||||||
Write-Host "注意:node.exe 位于用户目录($nodeExe,nvm/便携版?)。SYSTEM 账户一般也能运行它;若服务起不来,请改用 winget / 官网安装包安装的 Node.js。" -ForegroundColor Yellow
|
Write-Host "注意:node.exe 位于用户目录($nodeExe,nvm/便携版?)。SYSTEM 账户一般也能运行它;若服务起不来,请改用 winget / 官网安装包安装的 Node.js。" -ForegroundColor Yellow
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -20,8 +20,8 @@ import fs from 'node:fs';
|
|||||||
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
||||||
const IS_WIN = process.platform === 'win32';
|
const IS_WIN = process.platform === 'win32';
|
||||||
|
|
||||||
if (Number(process.versions.node.split('.')[0]) < 18) {
|
if (Number(process.versions.node.split('.')[0]) < 22) {
|
||||||
console.error(`Node.js ${process.versions.node} 太旧,需要 18 或更高(推荐 22 LTS):https://nodejs.org/zh-cn/download`);
|
console.error(`Node.js ${process.versions.node} 太旧,需要 22 或更高(22 / 24 LTS):https://nodejs.org/zh-cn/download`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ cd /d "%~dp0.."
|
|||||||
|
|
||||||
where node >nul 2>nul
|
where node >nul 2>nul
|
||||||
if errorlevel 1 goto :nonode
|
if errorlevel 1 goto :nonode
|
||||||
node -e "process.exit(Number(process.versions.node.split('.')[0])>=18?0:1)"
|
node -e "process.exit(Number(process.versions.node.split('.')[0])>=22?0:1)"
|
||||||
if errorlevel 1 goto :oldnode
|
if errorlevel 1 goto :oldnode
|
||||||
|
|
||||||
if not exist "node_modules\ws\package.json" (
|
if not exist "node_modules\ws\package.json" (
|
||||||
@@ -25,7 +25,7 @@ exit /b 0
|
|||||||
|
|
||||||
:nonode
|
:nonode
|
||||||
echo.
|
echo.
|
||||||
echo 未找到 Node.js(需要 18 或更高,推荐 22 LTS)。Node.js not found.
|
echo 未找到 Node.js(需要 22 或更高,22 / 24 LTS)。Node.js not found.
|
||||||
echo.
|
echo.
|
||||||
echo 方法一:在 PowerShell 或命令提示符中运行
|
echo 方法一:在 PowerShell 或命令提示符中运行
|
||||||
echo winget install OpenJS.NodeJS.LTS
|
echo winget install OpenJS.NodeJS.LTS
|
||||||
@@ -38,7 +38,7 @@ exit /b 1
|
|||||||
|
|
||||||
:oldnode
|
:oldnode
|
||||||
echo.
|
echo.
|
||||||
for /f "delims=" %%v in ('node -v') do echo 当前 Node.js 版本 %%v 太旧,需要 18 或更高(推荐 22 LTS)。
|
for /f "delims=" %%v in ('node -v') do echo 当前 Node.js 版本 %%v 太旧,需要 22 或更高(22 / 24 LTS)。
|
||||||
echo 升级:winget upgrade OpenJS.NodeJS.LTS 或 https://nodejs.org/zh-cn/download
|
echo 升级:winget upgrade OpenJS.NodeJS.LTS 或 https://nodejs.org/zh-cn/download
|
||||||
echo.
|
echo.
|
||||||
pause
|
pause
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ function Test-Node {
|
|||||||
|
|
||||||
$node = Test-Node
|
$node = Test-Node
|
||||||
if (-not $node) {
|
if (-not $node) {
|
||||||
Write-Host '未找到 Node.js(需要 18 或更高,推荐 22 LTS)。' -ForegroundColor Yellow
|
Write-Host '未找到 Node.js(需要 22 或更高,22 / 24 LTS)。' -ForegroundColor Yellow
|
||||||
$winget = Get-Command winget -ErrorAction SilentlyContinue
|
$winget = Get-Command winget -ErrorAction SilentlyContinue
|
||||||
if ($winget) {
|
if ($winget) {
|
||||||
Write-Host '可以用 Windows 自带的 winget 安装: winget install OpenJS.NodeJS.LTS'
|
Write-Host '可以用 Windows 自带的 winget 安装: winget install OpenJS.NodeJS.LTS'
|
||||||
@@ -49,8 +49,8 @@ if (-not $node) {
|
|||||||
Pause-Exit 1
|
Pause-Exit 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($node.Major -lt 18) {
|
if ($node.Major -lt 22) {
|
||||||
Write-Host "Node.js $($node.Version) 太旧,需要 18 或更高:winget upgrade OpenJS.NodeJS.LTS 或 https://nodejs.org/zh-cn/download" -ForegroundColor Red
|
Write-Host "Node.js $($node.Version) 太旧,需要 22 或更高:winget upgrade OpenJS.NodeJS.LTS 或 https://nodejs.org/zh-cn/download" -ForegroundColor Red
|
||||||
Pause-Exit 1
|
Pause-Exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -1,12 +1,12 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# 卫戍协议:盟约 · macOS / Linux start script. Docs: docs/DEPLOY.md
|
# 卫戍协议:盟约 · macOS / Linux start script. Docs: docs/DEPLOY.md
|
||||||
# scripts/start.sh [--port 3001] [--no-open] [--no-local] [--no-assets] … (arguments go to scripts/launch.mjs)
|
# scripts/start.sh [--port 3001] [--no-open] [--no-local] [--no-assets] … (arguments go to scripts/launch.mjs)
|
||||||
# Checks Node.js ≥ 18, runs `npm ci` on the first run, then scripts/launch.mjs (tools/setup.mjs → server → browser).
|
# Checks Node.js ≥ 22, runs `npm ci` on the first run, then scripts/launch.mjs (tools/setup.mjs → server → browser).
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
cd "$(dirname "$0")/.."
|
cd "$(dirname "$0")/.."
|
||||||
|
|
||||||
if ! command -v node >/dev/null 2>&1; then
|
if ! command -v node >/dev/null 2>&1; then
|
||||||
echo "未找到 Node.js(需要 18 或更高,推荐 22 LTS)。Node.js not found."
|
echo "未找到 Node.js(需要 22 或更高,22 / 24 LTS)。Node.js not found."
|
||||||
if [ "$(uname -s)" = "Darwin" ]; then
|
if [ "$(uname -s)" = "Darwin" ]; then
|
||||||
echo " 安装:brew install node@22 或 https://nodejs.org/zh-cn/download"
|
echo " 安装:brew install node@22 或 https://nodejs.org/zh-cn/download"
|
||||||
else
|
else
|
||||||
@@ -14,8 +14,8 @@ if ! command -v node >/dev/null 2>&1; then
|
|||||||
fi
|
fi
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
if ! node -e "process.exit(Number(process.versions.node.split('.')[0])>=18?0:1)"; then
|
if ! node -e "process.exit(Number(process.versions.node.split('.')[0])>=22?0:1)"; then
|
||||||
echo "Node.js $(node -v) 太旧,需要 18 或更高(推荐 22 LTS):https://nodejs.org/zh-cn/download"
|
echo "Node.js $(node -v) 太旧,需要 22 或更高(22 / 24 LTS):https://nodejs.org/zh-cn/download"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -164,7 +164,7 @@ async function main() {
|
|||||||
|
|
||||||
section('运行环境');
|
section('运行环境');
|
||||||
const node = checkNode();
|
const node = checkNode();
|
||||||
row(node.ok ? (node.recommended ? 'ok' : 'warn') : 'err', 'Node.js', `v${node.version}` + (node.ok ? (node.recommended ? '' : '(推荐 22 LTS)') : `(需要 ≥ ${MIN_NODE}:https://nodejs.org/zh-cn/download)`));
|
row(node.ok ? (node.recommended ? 'ok' : 'warn') : 'err', 'Node.js', `v${node.version}` + (node.ok ? (node.recommended ? '' : '(推荐 22 / 24 LTS)') : `(需要 ≥ ${MIN_NODE}:https://nodejs.org/zh-cn/download)`));
|
||||||
const npmV = tool(IS_WIN ? 'npm.cmd' : 'npm', ['--version']);
|
const npmV = tool(IS_WIN ? 'npm.cmd' : 'npm', ['--version']);
|
||||||
row(npmV ? 'ok' : 'warn', 'npm', npmV ? `v${npmV}` : '未找到(安装 Node.js 时会自带)');
|
row(npmV ? 'ok' : 'warn', 'npm', npmV ? `v${npmV}` : '未找到(安装 Node.js 时会自带)');
|
||||||
|
|
||||||
|
|||||||
+5
-5
@@ -4,7 +4,7 @@
|
|||||||
// node tools/setup.mjs [options]
|
// node tools/setup.mjs [options]
|
||||||
//
|
//
|
||||||
// Steps (each one is skipped when already done, so re-running is cheap — the start scripts run it on every start):
|
// Steps (each one is skipped when already done, so re-running is cheap — the start scripts run it on every start):
|
||||||
// 1. Node.js ≥ 18 check (clear message + download link otherwise).
|
// 1. Node.js ≥ 22 check (clear message + download link otherwise).
|
||||||
// 2. Dependencies: `npm ci` (falls back to `npm install`) when node_modules is missing or incomplete.
|
// 2. Dependencies: `npm ci` (falls back to `npm install`) when node_modules is missing or incomplete.
|
||||||
// 3. Client libraries in public/vendor (tools/vendor.mjs) when any is missing.
|
// 3. Client libraries in public/vendor (tools/vendor.mjs) when any is missing.
|
||||||
// 4. Game data (data/*.json, committed) present and parseable.
|
// 4. Game data (data/*.json, committed) present and parseable.
|
||||||
@@ -37,7 +37,7 @@ import { spawnSync } from 'node:child_process';
|
|||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
|
|
||||||
export const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
export const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
||||||
export const MIN_NODE = 18;
|
export const MIN_NODE = 22;
|
||||||
export const IS_WIN = process.platform === 'win32';
|
export const IS_WIN = process.platform === 'win32';
|
||||||
export const IS_MAC = process.platform === 'darwin';
|
export const IS_MAC = process.platform === 'darwin';
|
||||||
const NODE_URL = 'https://nodejs.org/zh-cn/download';
|
const NODE_URL = 'https://nodejs.org/zh-cn/download';
|
||||||
@@ -133,7 +133,7 @@ async function ask(question, def, timeoutMs = 60000) {
|
|||||||
/** Node.js version check. */
|
/** Node.js version check. */
|
||||||
export function checkNode() {
|
export function checkNode() {
|
||||||
const major = nodeMajor();
|
const major = nodeMajor();
|
||||||
return { ok: major >= MIN_NODE, version: process.versions.node, major, recommended: major >= 20 };
|
return { ok: major >= MIN_NODE, version: process.versions.node, major, recommended: major >= MIN_NODE };
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Runtime dependencies installed? */
|
/** Runtime dependencies installed? */
|
||||||
@@ -353,11 +353,11 @@ async function main() {
|
|||||||
// 1. Node
|
// 1. Node
|
||||||
const node = checkNode();
|
const node = checkNode();
|
||||||
if (!node.ok) {
|
if (!node.ok) {
|
||||||
log(`${mark.err} Node.js ${node.version} 太旧:需要 ${MIN_NODE} 或更高(推荐 22 LTS)。`);
|
log(`${mark.err} Node.js ${node.version} 太旧:需要 ${MIN_NODE} 或更高(22 / 24 LTS)。`);
|
||||||
log(` 下载:${NODE_URL}` + (IS_WIN ? ' 或在终端运行:winget install OpenJS.NodeJS.LTS' : IS_MAC ? ' 或:brew install node@22' : ''));
|
log(` 下载:${NODE_URL}` + (IS_WIN ? ' 或在终端运行:winget install OpenJS.NodeJS.LTS' : IS_MAC ? ' 或:brew install node@22' : ''));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
add('ok', 'Node.js', `v${node.version}${node.recommended ? '' : '(可用;推荐升级到 22 LTS)'}`);
|
add('ok', 'Node.js', `v${node.version}${node.recommended ? '' : '(可用;推荐 22 / 24 LTS)'}`);
|
||||||
|
|
||||||
// 2. npm dependencies
|
// 2. npm dependencies
|
||||||
let deps = checkDeps();
|
let deps = checkDeps();
|
||||||
|
|||||||
Reference in new issue
Block a user