ink icon indicating copy to clipboard operation
ink copied to clipboard

Wait for Ink to finish any pending renders before process exit

Open kevinschaich opened this issue 4 months ago • 1 comments

I have a custom logger class which uses Ink.

If I hit an exception anywhere in my application, the parent process immediately exits and stops Ink from going through any final render cycles that would result in logs being printed.

If I put a timeout for 10ms directly before throwing an error, Ink finishes as expected. But I don't always know where errors are going to occur.

This is the best I've come up with in my logger class:

    private setupExitHandler() {
        const flush = async () => {
            // give Ink a bit of time to get one or two additional renders in
            await new Promise(resolve => setTimeout(resolve, 100))
        }
        process.on('uncaughtException', async error => {
            await flush()
            console.error(`${error.stack} ${error.message}`)
        })

        process.on('unhandledRejection', async reason => {
            await flush()
            const error = reason instanceof Error ? reason : new Error(String(reason))
            console.error(`${error.stack} ${error.message}`)
        })
    }

Is there a canonical/better way to do this?

kevinschaich avatar Oct 17 '25 03:10 kevinschaich

Calling instance.rerender(sameRootNode) will force a synchronous render, after that you can await writing to stdout yourself, once that resolves output should be synchronized.

Something like this:

async function flush(instance, rootNode) {
  instance.rerender(rootNode)
  instance.rerender(null) // maybe unmount the tree for cleanup?
  await new Promise(resolve => proces.stdout.write("", resolve)) // ensure all updates written
}

justjake avatar Oct 23 '25 17:10 justjake