-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathserver.js
More file actions
114 lines (102 loc) · 3.78 KB
/
server.js
File metadata and controls
114 lines (102 loc) · 3.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import express from 'express';
import http from 'http';
import fs from 'fs/promises';
import { createServer as createViteServer } from 'vite';
import { Server as IOServer } from 'socket.io';
const app = express();
// Add headers for worker assets so cross-origin worker errors are not opaque
// and so misdetected .ts worker files are still served as JS by the browser.
//
// - If a worker resource is requested under /ontosphere/assets/*, set CORS so
// ErrorEvents are not opaque.
// - If a worker asset path ends with ".ts" (leftover built filename), force the
// Content-Type to "application/javascript" so the browser will attempt to execute it.
// This is a temporary server-side safeguard; the proper fix is to ensure built
// assets are emitted with .js extension and served with the correct MIME.
app.use((_req, res, next) => {
res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
res.setHeader('Cross-Origin-Embedder-Policy', 'credentialless');
next();
});
app.use((req, res, next) => {
if (req.method === 'GET' && req.originalUrl && req.originalUrl.startsWith('/ontosphere/assets/')) {
res.setHeader('Access-Control-Allow-Origin', '*');
// If the asset ends with .ts, some servers may wrongly detect a binary MIME.
// Force JS MIME type so the browser will try to execute the worker.
if (req.originalUrl.endsWith('.ts')) {
res.setHeader('Content-Type', 'application/javascript');
}
}
next();
});
const server = http.createServer(app);
const PORT = process.env.PORT || 8080;
(async () => {
// Start Vite in middleware mode so the app is served via this Node server.
// This keeps a single process that also hosts the socket.io control channel.
const vite = await createViteServer({
server: { middlewareMode: 'html' },
appType: 'custom',
});
// Use Vite's connect instance as middleware
app.use(vite.middlewares);
// SPA fallback: serve index.html for unknown routes (so "/" and client-side routes work)
// Use a generic middleware instead of an express path pattern to avoid path-to-regexp parsing issues.
app.use(async (req, res, next) => {
// Ignore non-GET requests and socket.io traffic
if (req.method !== 'GET' || req.originalUrl.startsWith('/socket.io')) {
return next();
}
try {
const url = req.originalUrl;
const indexHtml = await fs.readFile('index.html', 'utf-8');
const transformed = await vite.transformIndexHtml(url, indexHtml);
res.statusCode = 200;
res.setHeader('Content-Type', 'text/html');
res.end(transformed);
} catch (e) {
vite.ssrFixStacktrace?.(e);
next(e);
}
});
// Start HTTP server
server.listen(PORT, () => {
console.log(`Dev server listening on http://localhost:${PORT}`);
console.log('Use "npm run stop" to trigger a graceful stop via socket.');
});
// Socket.IO for stop command
const io = new IOServer(server, {
// Restrict CORS to localhost - adjust as needed.
cors: {
origin: `http://localhost:${PORT}`,
methods: ['GET', 'POST']
}
});
io.on('connection', (socket) => {
console.log('stop socket connected');
socket.on('npmStop', () => {
console.log('npmStop received — shutting down');
// Close Vite server (if available), then exit.
(async () => {
try {
await vite.close();
} catch (e) {
// ignore
}
// close http server then exit
server.close(() => {
console.log('HTTP server closed, exiting process.');
process.exit(0);
});
// In case server.close hangs, force exit after timeout
setTimeout(() => {
console.log('Forcing exit.');
process.exit(0);
}, 2000);
})();
});
socket.on('disconnect', () => {
// ignore
});
});
})();