1
This commit is contained in:
@@ -1,11 +1,12 @@
|
||||
import net from 'node:net';
|
||||
import path from 'node:path';
|
||||
import {spawn} from 'node:child_process';
|
||||
import {existsSync, readFileSync} from 'node:fs';
|
||||
import net from 'node:net';
|
||||
import path from 'node:path';
|
||||
import {fileURLToPath, pathToFileURL} from 'node:url';
|
||||
|
||||
const repoRoot = fileURLToPath(new URL('../', import.meta.url));
|
||||
const serverRoot = fileURLToPath(new URL('../server-node/', import.meta.url));
|
||||
const serverRsRoot = fileURLToPath(new URL('../server-rs/', import.meta.url));
|
||||
const viteCliPath = fileURLToPath(new URL('./vite-cli.mjs', import.meta.url));
|
||||
const serverTsxCliPath = fileURLToPath(
|
||||
new URL('../server-node/node_modules/tsx/dist/cli.mjs', import.meta.url),
|
||||
@@ -16,6 +17,8 @@ const serverTsxLoaderPath = fileURLToPath(
|
||||
const serverTsxLoaderUrl = pathToFileURL(serverTsxLoaderPath).href;
|
||||
const envExamplePath = fileURLToPath(new URL('../.env.example', import.meta.url));
|
||||
const envLocalPath = fileURLToPath(new URL('../.env.local', import.meta.url));
|
||||
const spacetimeConfigPath = fileURLToPath(new URL('../spacetime.json', import.meta.url));
|
||||
const spacetimeLocalConfigPath = fileURLToPath(new URL('../spacetime.local.json', import.meta.url));
|
||||
const bundledNodePath = fileURLToPath(
|
||||
new URL('../.tools/node-v22.22.2-win-x64/node.exe', import.meta.url),
|
||||
);
|
||||
@@ -25,6 +28,11 @@ const bundledNpmCliPath = fileURLToPath(
|
||||
const npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
||||
const DEFAULT_DEV_DATABASE_URL = 'postgresql://postgres:postgres@127.0.0.1:5432/genarrative';
|
||||
const DEV_MEMORY_DATABASE_URL = 'pg-mem://genarrative-dev';
|
||||
const DEFAULT_RUST_API_HOST = '127.0.0.1';
|
||||
const DEFAULT_RUST_API_PORT = '3100';
|
||||
const DEFAULT_SPACETIME_SERVER_URL = 'http://127.0.0.1:3001';
|
||||
const DEFAULT_SPACETIME_DATABASE = 'genarrative-dev';
|
||||
const DEFAULT_INTERNAL_API_SECRET = 'genarrative-dev-internal-bridge';
|
||||
|
||||
function parseEnvContents(contents) {
|
||||
return contents
|
||||
@@ -63,6 +71,18 @@ function readEnvFile(filePath) {
|
||||
return parseEnvContents(readFileSync(filePath, 'utf8'));
|
||||
}
|
||||
|
||||
function readJsonFile(filePath) {
|
||||
if (!existsSync(filePath)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return JSON.parse(readFileSync(filePath, 'utf8'));
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function resolveDatabaseProbeTarget(databaseUrl) {
|
||||
const trimmed = databaseUrl.trim();
|
||||
if (!trimmed || !/^postgres(?:ql)?:\/\//u.test(trimmed)) {
|
||||
@@ -177,6 +197,8 @@ function prependEnvPath(envMap, nextEntry) {
|
||||
|
||||
const exampleEnv = readEnvFile(envExamplePath);
|
||||
const localEnv = readEnvFile(envLocalPath);
|
||||
const spacetimeConfig = readJsonFile(spacetimeConfigPath);
|
||||
const spacetimeLocalConfig = readJsonFile(spacetimeLocalConfigPath);
|
||||
|
||||
const mergedEnv = {
|
||||
...exampleEnv,
|
||||
@@ -196,6 +218,22 @@ mergedEnv.PROJECT_ROOT = mergedEnv.PROJECT_ROOT || repoRoot;
|
||||
mergedEnv.NODE_SERVER_ADDR = mergedEnv.NODE_SERVER_ADDR || ':8081';
|
||||
mergedEnv.NODE_SERVER_TARGET =
|
||||
mergedEnv.NODE_SERVER_TARGET || resolveServerTarget(mergedEnv.NODE_SERVER_ADDR);
|
||||
mergedEnv.GENARRATIVE_API_HOST =
|
||||
mergedEnv.GENARRATIVE_API_HOST || DEFAULT_RUST_API_HOST;
|
||||
mergedEnv.GENARRATIVE_API_PORT =
|
||||
mergedEnv.GENARRATIVE_API_PORT || DEFAULT_RUST_API_PORT;
|
||||
mergedEnv.GENARRATIVE_API_TARGET =
|
||||
mergedEnv.GENARRATIVE_API_TARGET ||
|
||||
`http://${mergedEnv.GENARRATIVE_API_HOST}:${mergedEnv.GENARRATIVE_API_PORT}`;
|
||||
mergedEnv.GENARRATIVE_INTERNAL_API_SECRET =
|
||||
mergedEnv.GENARRATIVE_INTERNAL_API_SECRET || DEFAULT_INTERNAL_API_SECRET;
|
||||
mergedEnv.GENARRATIVE_SPACETIME_SERVER_URL =
|
||||
mergedEnv.GENARRATIVE_SPACETIME_SERVER_URL || DEFAULT_SPACETIME_SERVER_URL;
|
||||
mergedEnv.GENARRATIVE_SPACETIME_DATABASE =
|
||||
mergedEnv.GENARRATIVE_SPACETIME_DATABASE ||
|
||||
spacetimeLocalConfig?.database ||
|
||||
spacetimeConfig?.database ||
|
||||
DEFAULT_SPACETIME_DATABASE;
|
||||
mergedEnv.DATABASE_URL =
|
||||
mergedEnv.DATABASE_URL || DEFAULT_DEV_DATABASE_URL;
|
||||
mergedEnv.VITE_DEV_HOST = mergedEnv.VITE_DEV_HOST || '127.0.0.1';
|
||||
@@ -205,9 +243,23 @@ mergedEnv.npm_config_scripts_prepend_node_path = 'true';
|
||||
const exampleDatabaseUrl = `${exampleEnv.DATABASE_URL || ''}`.trim();
|
||||
const localDatabaseUrl = `${localEnv.DATABASE_URL || ''}`.trim();
|
||||
const processDatabaseUrl = `${process.env.DATABASE_URL || ''}`.trim();
|
||||
const exampleSpacetimeDatabase = `${exampleEnv.GENARRATIVE_SPACETIME_DATABASE || ''}`.trim();
|
||||
const localSpacetimeDatabase = `${localEnv.GENARRATIVE_SPACETIME_DATABASE || ''}`.trim();
|
||||
const processSpacetimeDatabase = `${process.env.GENARRATIVE_SPACETIME_DATABASE || ''}`.trim();
|
||||
const hasExplicitDatabaseUrl =
|
||||
Boolean(processDatabaseUrl) ||
|
||||
(Boolean(localDatabaseUrl) && localDatabaseUrl !== exampleDatabaseUrl);
|
||||
const hasExplicitSpacetimeDatabase =
|
||||
Boolean(processSpacetimeDatabase) ||
|
||||
(Boolean(localSpacetimeDatabase) && localSpacetimeDatabase !== exampleSpacetimeDatabase);
|
||||
|
||||
// 本地开发默认跟随仓库当前的 Spacetime 数据库名,只有显式覆盖时才尊重环境变量。
|
||||
if (!hasExplicitSpacetimeDatabase) {
|
||||
mergedEnv.GENARRATIVE_SPACETIME_DATABASE =
|
||||
spacetimeLocalConfig?.database ||
|
||||
spacetimeConfig?.database ||
|
||||
DEFAULT_SPACETIME_DATABASE;
|
||||
}
|
||||
|
||||
if (!hasExplicitDatabaseUrl) {
|
||||
const databaseProbeTarget = resolveDatabaseProbeTarget(mergedEnv.DATABASE_URL);
|
||||
@@ -228,6 +280,14 @@ if (!hasExplicitDatabaseUrl) {
|
||||
console.log(`[dev:node] PROJECT_ROOT=${mergedEnv.PROJECT_ROOT}`);
|
||||
console.log(`[dev:node] NODE_SERVER_ADDR=${mergedEnv.NODE_SERVER_ADDR}`);
|
||||
console.log(`[dev:node] NODE_SERVER_TARGET=${mergedEnv.NODE_SERVER_TARGET}`);
|
||||
console.log(`[dev:node] GENARRATIVE_API_TARGET=${mergedEnv.GENARRATIVE_API_TARGET}`);
|
||||
console.log('[dev:node] GENARRATIVE_INTERNAL_API_SECRET=[configured]');
|
||||
console.log(
|
||||
`[dev:node] GENARRATIVE_SPACETIME_SERVER_URL=${mergedEnv.GENARRATIVE_SPACETIME_SERVER_URL}`,
|
||||
);
|
||||
console.log(
|
||||
`[dev:node] GENARRATIVE_SPACETIME_DATABASE=${mergedEnv.GENARRATIVE_SPACETIME_DATABASE}`,
|
||||
);
|
||||
console.log(`[dev:node] DATABASE_URL=${redactDatabaseUrl(mergedEnv.DATABASE_URL)}`);
|
||||
console.log(`[dev:node] VITE_DEV_HOST=${mergedEnv.VITE_DEV_HOST}`);
|
||||
console.log(`[dev:node] NODE_RUNTIME=${runtimeNodePath}`);
|
||||
@@ -329,6 +389,38 @@ const serverProcess = existsSync(serverTsxLoaderPath)
|
||||
stdio: 'inherit',
|
||||
});
|
||||
|
||||
const rustApiProcess = process.platform === 'win32'
|
||||
? spawn(
|
||||
'powershell',
|
||||
[
|
||||
'-NoProfile',
|
||||
'-ExecutionPolicy',
|
||||
'Bypass',
|
||||
'-File',
|
||||
path.join(serverRsRoot, 'scripts', 'dev.ps1'),
|
||||
'-ApiHost',
|
||||
mergedEnv.GENARRATIVE_API_HOST,
|
||||
'-Port',
|
||||
mergedEnv.GENARRATIVE_API_PORT,
|
||||
],
|
||||
{
|
||||
cwd: repoRoot,
|
||||
env: mergedEnv,
|
||||
stdio: 'inherit',
|
||||
},
|
||||
)
|
||||
: spawn(
|
||||
'bash',
|
||||
[
|
||||
path.join(serverRsRoot, 'scripts', 'dev.sh'),
|
||||
],
|
||||
{
|
||||
cwd: repoRoot,
|
||||
env: mergedEnv,
|
||||
stdio: 'inherit',
|
||||
},
|
||||
);
|
||||
|
||||
const viteProcess = spawn(
|
||||
runtimeNodePath,
|
||||
[viteCliPath, '--port=3000', `--host=${mergedEnv.VITE_DEV_HOST}`],
|
||||
@@ -340,6 +432,7 @@ const viteProcess = spawn(
|
||||
);
|
||||
|
||||
registerChild('node server', serverProcess, () => viteProcess);
|
||||
registerChild('rust api-server', rustApiProcess, () => viteProcess);
|
||||
registerChild('vite dev server', viteProcess, () => serverProcess);
|
||||
|
||||
process.on('SIGINT', () => {
|
||||
|
||||
Reference in New Issue
Block a user