-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
feat(scripts): salvage single-mode, IPC readiness, framework resolver and esbuild plugins #5862
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
base: next
Are you sure you want to change the base?
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 |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| const http = require('node:http'); | ||
| const { debuglog } = require('node:util'); | ||
|
|
||
| const { importModule } = require('@eggjs/utils'); | ||
|
|
||
| const debug = debuglog('egg/scripts/start-single/cjs'); | ||
|
|
||
| async function main() { | ||
| debug('argv: %o', process.argv); | ||
| const options = JSON.parse(process.argv[2]); | ||
| debug('start single options: %o', options); | ||
| const exports = await importModule(options.framework); | ||
| let startEgg = exports.start ?? exports.startEgg; | ||
| if (typeof startEgg !== 'function') { | ||
| startEgg = exports.default?.start ?? exports.default?.startEgg; | ||
| } | ||
| if (typeof startEgg !== 'function') { | ||
| throw new Error(`Cannot find start/startEgg function from framework: ${options.framework}`); | ||
| } | ||
| const app = await startEgg({ | ||
| baseDir: options.baseDir, | ||
| framework: options.framework, | ||
| env: options.env, | ||
| mode: 'single', | ||
| }); | ||
|
|
||
| const port = options.port ?? 7001; | ||
| const server = http.createServer(app.callback()); | ||
| app.emit('server', server); | ||
|
|
||
| await new Promise((resolve, reject) => { | ||
| server.listen(port, () => { | ||
| resolve(undefined); | ||
| }); | ||
| server.once('error', reject); | ||
| }); | ||
|
|
||
| const address = server.address(); | ||
| const url = typeof address === 'string' ? address : `http://127.0.0.1:${address.port}`; | ||
|
|
||
| debug('server started on %s', url); | ||
|
|
||
| // notify parent process (daemon mode) | ||
| if (process.send) { | ||
| process.send({ | ||
| action: 'egg-ready', | ||
| data: { address: url, port: address.port ?? port }, | ||
| }); | ||
| } | ||
|
|
||
| // graceful shutdown | ||
| const shutdown = async (signal) => { | ||
| debug('receive signal %s, closing server', signal); | ||
| server.close(() => { | ||
| debug('server closed'); | ||
| if (typeof app.close === 'function') { | ||
| app | ||
| .close() | ||
| .then(() => { | ||
| process.exit(0); | ||
| }) | ||
| .catch(() => { | ||
| process.exit(1); | ||
| }); | ||
| } else { | ||
| process.exit(0); | ||
| } | ||
| }); | ||
| // force exit after timeout | ||
| setTimeout(() => { | ||
| process.exit(1); | ||
| }, 10000).unref(); | ||
| }; | ||
|
|
||
| process.once('SIGTERM', () => shutdown('SIGTERM')); | ||
| process.once('SIGINT', () => shutdown('SIGINT')); | ||
| process.once('SIGQUIT', () => shutdown('SIGQUIT')); | ||
| } | ||
|
|
||
| main().catch((err) => { | ||
| console.error(err); | ||
| process.exit(1); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| import http from 'node:http'; | ||
| import { debuglog } from 'node:util'; | ||
|
|
||
| import { importModule } from '@eggjs/utils'; | ||
|
|
||
| const debug = debuglog('egg/scripts/start-single/esm'); | ||
|
|
||
| async function main() { | ||
| debug('argv: %o', process.argv); | ||
| const options = JSON.parse(process.argv[2]); | ||
| debug('start single options: %o', options); | ||
| const framework = await importModule(options.framework); | ||
| const startEgg = framework.start ?? framework.startEgg; | ||
| if (typeof startEgg !== 'function') { | ||
| throw new Error(`Cannot find start/startEgg function from framework: ${options.framework}`); | ||
|
Comment on lines
+13
to
+15
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.
The ESM single-process launcher only checks Useful? React with 👍 / 👎. |
||
| } | ||
|
Comment on lines
+12
to
+16
Contributor
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. The ESM version of the start script should also check for the .default export to be consistent with the CJS version and to support frameworks that use default exports. const framework = await importModule(options.framework);
let startEgg = framework.start ?? framework.startEgg;
if (typeof startEgg !== 'function') {
startEgg = framework.default?.start ?? framework.default?.startEgg;
}
if (typeof startEgg !== 'function') {
throw new Error("Cannot find start/startEgg function from framework: " + options.framework);
}
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| const app = await startEgg({ | ||
| baseDir: options.baseDir, | ||
| framework: options.framework, | ||
| env: options.env, | ||
| mode: 'single', | ||
| }); | ||
|
|
||
| const port = options.port ?? 7001; | ||
| const server = http.createServer(app.callback()); | ||
| app.emit('server', server); | ||
|
|
||
| await new Promise((resolve, reject) => { | ||
| server.listen(port, () => { | ||
| resolve(undefined); | ||
| }); | ||
| server.once('error', reject); | ||
| }); | ||
|
|
||
| const address = server.address(); | ||
| const url = typeof address === 'string' ? address : `http://127.0.0.1:${address.port}`; | ||
|
|
||
| debug('server started on %s', url); | ||
|
|
||
| // notify parent process (daemon mode) | ||
| if (process.send) { | ||
| process.send({ | ||
| action: 'egg-ready', | ||
| data: { address: url, port: address.port ?? port }, | ||
| }); | ||
| } | ||
|
|
||
| // graceful shutdown | ||
| const shutdown = async (signal) => { | ||
| debug('receive signal %s, closing server', signal); | ||
| server.close(() => { | ||
| debug('server closed'); | ||
| if (typeof app.close === 'function') { | ||
| app | ||
| .close() | ||
| .then(() => { | ||
| process.exit(0); | ||
| }) | ||
| .catch(() => { | ||
| process.exit(1); | ||
| }); | ||
| } else { | ||
| process.exit(0); | ||
| } | ||
| }); | ||
| // force exit after timeout | ||
| setTimeout(() => { | ||
| process.exit(1); | ||
| }, 10000).unref(); | ||
| }; | ||
|
|
||
| process.once('SIGTERM', () => shutdown('SIGTERM')); | ||
| process.once('SIGINT', () => shutdown('SIGINT')); | ||
| process.once('SIGQUIT', () => shutdown('SIGQUIT')); | ||
| } | ||
|
|
||
| main().catch((err) => { | ||
| console.error(err); | ||
| process.exit(1); | ||
| }); | ||
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.
🧩 Analysis chain
🏁 Script executed:
fd -t f "start-single\.(cjs|mjs)" tools/Repository: eggjs/egg
Length of output: 130
🏁 Script executed:
Repository: eggjs/egg
Length of output: 2872
🏁 Script executed:
Repository: eggjs/egg
Length of output: 2732
🏁 Script executed:
Repository: eggjs/egg
Length of output: 88
🏁 Script executed:
cat -n tools/scripts/src/commands/start.ts | head -100Repository: eggjs/egg
Length of output: 3912
🏁 Script executed:
Repository: eggjs/egg
Length of output: 4863
🏁 Script executed:
Repository: eggjs/egg
Length of output: 2704
Align framework-entry fallback behavior between CJS and ESM launchers.
The
.cjslauncher checksexports.default?.startandexports.default?.startEggas a fallback (lines 15), but the.mjslauncher skips this step entirely and throws if the named export is not found. SincegetServerBin()selects the launcher based onthis.isESMat runtime, single-process startup will behave differently depending on which binary is used. Updatestart-single.mjsto mirror the fallback logic:🤖 Prompt for AI Agents