Compare commits
3 commits
next
...
metrics-se
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3345abecf3 | ||
|
|
9d9e1d9b24 | ||
|
|
c27e3b46ec |
6 changed files with 204 additions and 1 deletions
|
|
@ -7,6 +7,7 @@
|
|||
"dev-proxy": "node server.js",
|
||||
"start": "run-p dev-proxy dev-rsbuild watch-mesher",
|
||||
"start2": "run-p dev-rsbuild watch-mesher",
|
||||
"start-metrics": "ENABLE_METRICS=true rsbuild dev",
|
||||
"build": "pnpm build-other-workers && rsbuild build",
|
||||
"build-analyze": "BUNDLE_ANALYZE=true rsbuild build && pnpm build-other-workers",
|
||||
"build-single-file": "SINGLE_FILE_BUILD=true rsbuild build",
|
||||
|
|
@ -32,7 +33,8 @@
|
|||
"run-all": "run-p start run-playground",
|
||||
"build-playground": "rsbuild build --config renderer/rsbuild.config.ts",
|
||||
"watch-playground": "rsbuild dev --config renderer/rsbuild.config.ts",
|
||||
"update-git-deps": "tsx scripts/updateGitDeps.ts"
|
||||
"update-git-deps": "tsx scripts/updateGitDeps.ts",
|
||||
"request-data": "tsx scripts/requestData.ts"
|
||||
},
|
||||
"keywords": [
|
||||
"prismarine",
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import { appAndRendererSharedConfig } from './renderer/rsbuildSharedConfig'
|
|||
import { genLargeDataAliases } from './scripts/genLargeDataAliases'
|
||||
import sharp from 'sharp'
|
||||
import supportedVersions from './src/supportedVersions.mjs'
|
||||
import { startWsServer } from './scripts/wsServer'
|
||||
|
||||
const SINGLE_FILE_BUILD = process.env.SINGLE_FILE_BUILD === 'true'
|
||||
|
||||
|
|
@ -59,6 +60,8 @@ const configSource = (SINGLE_FILE_BUILD ? 'BUNDLED' : (process.env.CONFIG_JSON_S
|
|||
|
||||
const faviconPath = 'favicon.png'
|
||||
|
||||
const enableMetrics = process.env.ENABLE_METRICS === 'true'
|
||||
|
||||
// base options are in ./renderer/rsbuildSharedConfig.ts
|
||||
const appConfig = defineConfig({
|
||||
html: {
|
||||
|
|
@ -159,6 +162,7 @@ const appConfig = defineConfig({
|
|||
'process.env.INLINED_APP_CONFIG': JSON.stringify(configSource === 'BUNDLED' ? configJson : null),
|
||||
'process.env.ENABLE_COOKIE_STORAGE': JSON.stringify(process.env.ENABLE_COOKIE_STORAGE || true),
|
||||
'process.env.COOKIE_STORAGE_PREFIX': JSON.stringify(process.env.COOKIE_STORAGE_PREFIX || ''),
|
||||
'process.env.WS_PORT': JSON.stringify(enableMetrics ? 8081 : false),
|
||||
},
|
||||
},
|
||||
server: {
|
||||
|
|
@ -216,6 +220,12 @@ const appConfig = defineConfig({
|
|||
await execAsync('pnpm run build-mesher')
|
||||
}
|
||||
fs.writeFileSync('./dist/version.txt', buildingVersion, 'utf-8')
|
||||
|
||||
// Start WebSocket server in development
|
||||
if (dev && enableMetrics) {
|
||||
await startWsServer(8081, false)
|
||||
}
|
||||
|
||||
console.timeEnd('total-prep')
|
||||
}
|
||||
if (!dev) {
|
||||
|
|
|
|||
42
scripts/requestData.ts
Normal file
42
scripts/requestData.ts
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import WebSocket from 'ws'
|
||||
|
||||
function formatBytes(bytes: number) {
|
||||
return `${(bytes).toFixed(2)} MB`
|
||||
}
|
||||
|
||||
function formatTime(ms: number) {
|
||||
return `${(ms / 1000).toFixed(2)}s`
|
||||
}
|
||||
|
||||
const ws = new WebSocket('ws://localhost:8081')
|
||||
|
||||
ws.on('open', () => {
|
||||
console.log('Connected to metrics server, waiting for metrics...')
|
||||
})
|
||||
|
||||
ws.on('message', (data) => {
|
||||
try {
|
||||
const metrics = JSON.parse(data.toString())
|
||||
console.log('\nPerformance Metrics:')
|
||||
console.log('------------------')
|
||||
console.log(`Load Time: ${formatTime(metrics.loadTime)}`)
|
||||
console.log(`Memory Usage: ${formatBytes(metrics.memoryUsage)}`)
|
||||
console.log(`Timestamp: ${new Date(metrics.timestamp).toLocaleString()}`)
|
||||
if (!process.argv.includes('-f')) { // follow mode
|
||||
process.exit(0)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error parsing metrics:', error)
|
||||
}
|
||||
})
|
||||
|
||||
ws.on('error', (error) => {
|
||||
console.error('WebSocket error:', error)
|
||||
process.exit(1)
|
||||
})
|
||||
|
||||
// Exit if no metrics received after 5 seconds
|
||||
setTimeout(() => {
|
||||
console.error('Timeout waiting for metrics')
|
||||
process.exit(1)
|
||||
}, 5000)
|
||||
45
scripts/wsServer.ts
Normal file
45
scripts/wsServer.ts
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
import {WebSocketServer} from 'ws'
|
||||
|
||||
export function startWsServer(port: number = 8081, tryOtherPort: boolean = true): Promise<number> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const tryPort = (currentPort: number) => {
|
||||
const wss = new WebSocketServer({ port: currentPort })
|
||||
.on('listening', () => {
|
||||
console.log(`WebSocket server started on port ${currentPort}`)
|
||||
resolve(currentPort)
|
||||
})
|
||||
.on('error', (err: any) => {
|
||||
if (err.code === 'EADDRINUSE' && tryOtherPort) {
|
||||
console.log(`Port ${currentPort} in use, trying ${currentPort + 1}`)
|
||||
wss.close()
|
||||
tryPort(currentPort + 1)
|
||||
} else {
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
|
||||
wss.on('connection', (ws) => {
|
||||
console.log('Client connected')
|
||||
|
||||
ws.on('message', (message) => {
|
||||
try {
|
||||
// Simply relay the message to all connected clients except sender
|
||||
wss.clients.forEach(client => {
|
||||
if (client !== ws && client.readyState === WebSocket.OPEN) {
|
||||
client.send(message.toString())
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Error processing message:', error)
|
||||
}
|
||||
})
|
||||
|
||||
ws.on('close', () => {
|
||||
console.log('Client disconnected')
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
tryPort(port)
|
||||
})
|
||||
}
|
||||
103
src/devtools.ts
103
src/devtools.ts
|
|
@ -209,3 +209,106 @@ setInterval(() => {
|
|||
}, 1000)
|
||||
|
||||
// ---
|
||||
|
||||
// Add type declaration for performance.memory
|
||||
declare global {
|
||||
interface Performance {
|
||||
memory?: {
|
||||
usedJSHeapSize: number
|
||||
totalJSHeapSize: number
|
||||
jsHeapSizeLimit: number
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Performance metrics WebSocket client
|
||||
let ws: WebSocket | null = null
|
||||
let wsReconnectTimeout: NodeJS.Timeout | null = null
|
||||
let metricsInterval: NodeJS.Timeout | null = null
|
||||
|
||||
// Start collecting metrics immediately
|
||||
const startTime = performance.now()
|
||||
|
||||
function collectAndSendMetrics () {
|
||||
if (!ws || ws.readyState !== WebSocket.OPEN) return
|
||||
|
||||
const metrics = {
|
||||
loadTime: performance.now() - startTime,
|
||||
memoryUsage: (performance.memory?.usedJSHeapSize ?? 0) / 1024 / 1024,
|
||||
timestamp: Date.now()
|
||||
}
|
||||
|
||||
ws.send(JSON.stringify(metrics))
|
||||
}
|
||||
|
||||
function getWebSocketUrl () {
|
||||
const wsPort = process.env.WS_SERVER
|
||||
if (!wsPort) return null
|
||||
|
||||
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
|
||||
const { hostname } = window.location
|
||||
return `${protocol}//${hostname}:${wsPort}`
|
||||
}
|
||||
|
||||
function connectWebSocket () {
|
||||
if (ws) return
|
||||
|
||||
const wsUrl = getWebSocketUrl()
|
||||
if (!wsUrl) {
|
||||
console.log('WebSocket server not configured')
|
||||
return
|
||||
}
|
||||
|
||||
ws = new WebSocket(wsUrl)
|
||||
|
||||
ws.onopen = () => {
|
||||
console.log('Connected to metrics server')
|
||||
if (wsReconnectTimeout) {
|
||||
clearTimeout(wsReconnectTimeout)
|
||||
wsReconnectTimeout = null
|
||||
}
|
||||
|
||||
// Start sending metrics immediately after connection
|
||||
collectAndSendMetrics()
|
||||
|
||||
// Clear existing interval if any
|
||||
if (metricsInterval) {
|
||||
clearInterval(metricsInterval)
|
||||
}
|
||||
|
||||
// Set new interval
|
||||
metricsInterval = setInterval(collectAndSendMetrics, 500)
|
||||
}
|
||||
|
||||
ws.onclose = () => {
|
||||
console.log('Disconnected from metrics server')
|
||||
ws = null
|
||||
|
||||
// Clear metrics interval
|
||||
if (metricsInterval) {
|
||||
clearInterval(metricsInterval)
|
||||
metricsInterval = null
|
||||
}
|
||||
|
||||
// Try to reconnect after 3 seconds
|
||||
wsReconnectTimeout = setTimeout(connectWebSocket, 3000)
|
||||
}
|
||||
|
||||
ws.onerror = (error) => {
|
||||
console.error('WebSocket error:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// Connect immediately
|
||||
connectWebSocket()
|
||||
|
||||
// Add command to request current metrics
|
||||
window.requestMetrics = () => {
|
||||
const metrics = {
|
||||
loadTime: performance.now() - startTime,
|
||||
memoryUsage: (performance.memory?.usedJSHeapSize ?? 0) / 1024 / 1024,
|
||||
timestamp: Date.now()
|
||||
}
|
||||
console.log('Current metrics:', metrics)
|
||||
return metrics
|
||||
}
|
||||
|
|
|
|||
1
src/env.d.ts
vendored
1
src/env.d.ts
vendored
|
|
@ -3,6 +3,7 @@ declare namespace NodeJS {
|
|||
// Build configuration
|
||||
NODE_ENV: 'development' | 'production'
|
||||
SINGLE_FILE_BUILD?: string
|
||||
WS_SERVER?: string
|
||||
DISABLE_SERVICE_WORKER?: string
|
||||
CONFIG_JSON_SOURCE?: 'BUNDLED' | 'REMOTE'
|
||||
LOCAL_CONFIG_FILE?: string
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue