mirror of
https://github.com/hanzoai/next.js.git
synced 2026-09-24 17:00:51 +00:00
When cold-booting `next dev` on a fresh create-next-app, on the first server hit we need to fetch fonts and compile CSS, which takes up nearly half of the request time. It shouldn't be necessary to wait until the first server request to launch the first NodeJS process (eventually used for PostCSS processing in Tailwind). Once the server has started, we can anticipate that first request and pre-warm a single Node process. Because we grab the boot semaphore, if a request comes in as soon as the server is ready, it waits on the semaphore to resolve, and at most it takes as long as it would before this change. In all likelihood, the Node process is ready before any server request comes in. It also slightly saves time on `next build` I'd appreciate scrutiny of all the ways this can go wrong.
67 lines
1.9 KiB
JavaScript
67 lines
1.9 KiB
JavaScript
// Minimal Node.js worker that implements the turbopack-node pool wire protocol.
|
|
// Used by pool.rs integration tests.
|
|
//
|
|
// Wire protocol:
|
|
// - Messages are framed as [u32 BE length][payload bytes]
|
|
// - The ready signal is a 0-length message
|
|
// - After each TCP send, write "TURBOPACK_OUTPUT_D\n" to both stdout and stderr
|
|
// to signal the Rust side that console output for this operation is done.
|
|
|
|
const net = require('node:net')
|
|
|
|
const port = parseInt(process.argv[2], 10)
|
|
|
|
const socket = net.createConnection({ port, host: '127.0.0.1' }, () => {
|
|
socket.setNoDelay(true)
|
|
// Send empty ready signal (0-length message).
|
|
const readyBuf = Buffer.alloc(4)
|
|
readyBuf.writeUInt32BE(0, 0)
|
|
socket.write(readyBuf)
|
|
signalOutputDone()
|
|
})
|
|
|
|
// When the socket closes, exit cleanly.
|
|
socket.once('close', () => {
|
|
process.exit(0)
|
|
})
|
|
|
|
function signalOutputDone() {
|
|
process.stdout.write('TURBOPACK_OUTPUT_D\n')
|
|
process.stderr.write('TURBOPACK_OUTPUT_D\n')
|
|
}
|
|
|
|
function sendMessage(obj) {
|
|
const json = JSON.stringify(obj)
|
|
const payload = Buffer.from(json, 'utf8')
|
|
const header = Buffer.alloc(4)
|
|
header.writeUInt32BE(payload.length, 0)
|
|
socket.write(Buffer.concat([header, payload]))
|
|
signalOutputDone()
|
|
}
|
|
|
|
// --- Receive loop ---
|
|
// Read framed messages: 4-byte BE length prefix, then payload.
|
|
let recvBuf = Buffer.alloc(0)
|
|
|
|
socket.on('data', (chunk) => {
|
|
recvBuf = Buffer.concat([recvBuf, chunk])
|
|
drainMessages()
|
|
})
|
|
|
|
function drainMessages() {
|
|
while (true) {
|
|
if (recvBuf.length < 4) return
|
|
const len = recvBuf.readUInt32BE(0)
|
|
if (recvBuf.length < 4 + len) return
|
|
const payload = recvBuf.subarray(4, 4 + len)
|
|
recvBuf = recvBuf.subarray(4 + len)
|
|
handleMessage(JSON.parse(payload.toString('utf8')))
|
|
}
|
|
}
|
|
|
|
function handleMessage(msg) {
|
|
// Echo the message back along with this worker's PID so tests can verify
|
|
// whether the same process was reused across operations.
|
|
sendMessage({ echo: msg, pid: process.pid })
|
|
}
|