-
Notifications
You must be signed in to change notification settings - Fork 220
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add logic to represent booting state within preview panel and parse stdout from vite to get port #349
Add logic to represent booting state within preview panel and parse stdout from vite to get port #349
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,9 +18,16 @@ import { loadApp } from '../../apps/app.mjs'; | |
import { fileUpdated, pathToApp } from '../../apps/disk.mjs'; | ||
import { vite } from '../../exec.mjs'; | ||
|
||
const VITE_PORT_REGEX = /Local:.*http:\/\/localhost:([0-9]{1,4})/; | ||
|
||
type AppContextType = MessageContextType<'appId'>; | ||
|
||
const processes = new Map<string, ChildProcess>(); | ||
type ProcessMetadata = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this also have the status "running"? And potentially exit code |
||
process: ChildProcess; | ||
port: number | null; | ||
}; | ||
|
||
const processMetadata = new Map<string, ProcessMetadata>(); | ||
Comment on lines
+25
to
+30
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note that now, |
||
|
||
async function previewStart( | ||
_payload: PreviewStartPayloadType, | ||
|
@@ -33,41 +40,56 @@ async function previewStart( | |
return; | ||
} | ||
|
||
const existingProcess = processes.get(app.externalId); | ||
const existingProcess = processMetadata.get(app.externalId); | ||
|
||
if (existingProcess) { | ||
conn.reply(`app:${app.externalId}`, 'preview:status', { url: null, status: 'running' }); | ||
conn.reply(`app:${app.externalId}`, 'preview:status', { | ||
status: 'running', | ||
url: `http://localhost:${existingProcess.port}/`, | ||
}); | ||
return; | ||
} | ||
|
||
conn.reply(`app:${app.externalId}`, 'preview:status', { | ||
url: null, | ||
status: 'booting', | ||
}); | ||
|
||
const onChangePort = (newPort: number) => { | ||
processMetadata.set(app.externalId, { process, port: newPort }); | ||
conn.reply(`app:${app.externalId}`, 'preview:status', { | ||
url: `http://localhost:${newPort}/`, | ||
status: 'running', | ||
}); | ||
}; | ||
|
||
const process = vite({ | ||
// TODO: Configure port and fail if port in use | ||
args: [], | ||
cwd: pathToApp(app.externalId), | ||
stdout: (data) => { | ||
console.log(data.toString('utf8')); | ||
const encodedData = data.toString('utf8'); | ||
console.log(encodedData); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why the 2 lines? Is there a behavior change? |
||
|
||
const potentialPortMatch = VITE_PORT_REGEX.exec(encodedData); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It should be noted that chunks of data are not guaranteed to arrive deterministically in a way that we expect. This is why eg stream parsing is typically stateful. While I expect this to behave as we want it to, it's not guaranteed. |
||
if (potentialPortMatch) { | ||
const portString = potentialPortMatch[1]!; | ||
const port = parseInt(portString, 10); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
onChangePort(port); | ||
} | ||
}, | ||
stderr: (data) => { | ||
console.error(data.toString('utf8')); | ||
}, | ||
onExit: (_code) => { | ||
processes.delete(app.externalId); | ||
processMetadata.delete(app.externalId); | ||
conn.reply(`app:${app.externalId}`, 'preview:status', { | ||
url: null, | ||
status: 'stopped', | ||
}); | ||
}, | ||
}); | ||
|
||
processes.set(app.externalId, process); | ||
|
||
// TODO: better way to know when the server is ready | ||
setTimeout(() => { | ||
conn.reply(`app:${app.externalId}`, 'preview:status', { | ||
url: 'http://localhost:5174/', | ||
status: 'running', | ||
}); | ||
}, 500); | ||
processMetadata.set(app.externalId, { process, port: null }); | ||
} | ||
|
||
async function previewStop( | ||
|
@@ -81,14 +103,14 @@ async function previewStop( | |
return; | ||
} | ||
|
||
const process = processes.get(app.externalId); | ||
const result = processMetadata.get(app.externalId); | ||
|
||
if (!process) { | ||
if (!result) { | ||
conn.reply(`app:${app.externalId}`, 'preview:status', { url: null, status: 'stopped' }); | ||
return; | ||
} | ||
|
||
process.kill('SIGTERM'); | ||
result.process.kill('SIGTERM'); | ||
|
||
conn.reply(`app:${app.externalId}`, 'preview:status', { url: null, status: 'stopped' }); | ||
} | ||
|
@@ -117,13 +139,15 @@ export function register(wss: WebSocketServer) { | |
return; | ||
} | ||
|
||
const existingProcess = processes.get(app.externalId); | ||
const existingProcess = processMetadata.get(app.externalId); | ||
|
||
ws.send( | ||
JSON.stringify([ | ||
topic, | ||
'preview:status', | ||
{ url: null, status: existingProcess ? 'running' : 'stopped' }, | ||
existingProcess | ||
? { status: 'running', url: `http://localhost:${existingProcess.port}/` } | ||
: { url: null, status: 'stopped' }, | ||
]), | ||
); | ||
}); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's the regex for extracting the port vite picks from stdout.