@remotion/renderer
Version:
Render Remotion videos using Node.js or Bun
149 lines (148 loc) • 6.33 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.seekToFrame = exports.waitForReady = void 0;
const symbolicateable_error_1 = require("./error-handling/symbolicateable-error");
const logger_1 = require("./logger");
const parse_browser_error_stack_1 = require("./parse-browser-error-stack");
const puppeteer_evaluate_1 = require("./puppeteer-evaluate");
const cancelledToken = 'cancelled';
const readyToken = 'ready';
const waitForReady = ({ page, timeoutInMilliseconds, frame, indent, logLevel, }) => {
const cleanups = [];
const retrieveCancelledErrorAndReject = () => {
return new Promise((_, reject) => {
(0, puppeteer_evaluate_1.puppeteerEvaluateWithCatch)({
pageFunction: () => window.remotion_cancelledError,
args: [],
frame: null,
page,
timeoutInMilliseconds,
})
.then(({ value: val }) => {
if (typeof val !== 'string') {
reject(val);
return;
}
reject(new symbolicateable_error_1.SymbolicateableError({
frame: null,
stack: val,
name: 'CancelledError',
message: val.split('\n')[0],
stackFrame: (0, parse_browser_error_stack_1.parseStack)(val.split('\n')),
chunk: null,
}));
})
.catch((err) => {
logger_1.Log.verbose({ indent, logLevel }, 'Could not get cancelled error', err);
reject(new Error('Render was cancelled using cancelRender()'));
});
});
};
const waitForReadyProm = new Promise((resolve, reject) => {
const waitTask = page.mainFrame()._mainWorld.waitForFunction({
browser: page.browser,
// Increase timeout so the delayRender() timeout fires earlier
timeout: timeoutInMilliseconds + 3000,
pageFunction: `window.remotion_renderReady === true ? "${readyToken}" : window.remotion_cancelledError !== undefined ? "${cancelledToken}" : false`,
title: frame === null
? 'the page to render the React component'
: `the page to render the React component at frame ${frame}`,
});
cleanups.push(() => {
waitTask.terminate(new Error('cleanup'));
});
waitTask.promise
.then((a) => {
const token = a.toString();
if (token === cancelledToken) {
return retrieveCancelledErrorAndReject();
}
if (token === readyToken) {
return resolve(a);
}
reject(new Error('Unexpected token ' + token));
})
.catch((err) => {
if (err.message.includes('timeout') &&
err.message.includes('exceeded')) {
(0, puppeteer_evaluate_1.puppeteerEvaluateWithCatchAndTimeout)({
pageFunction: () => {
return Object.keys(window.remotion_delayRenderTimeouts)
.map((id, i) => {
const { label } = window.remotion_delayRenderTimeouts[id];
if (label === null) {
return `${i + 1}. (no label)`;
}
return `"${i + 1}. ${label}"`;
})
.join(', ');
},
args: [],
frame,
page,
timeoutInMilliseconds: 5000,
})
.then((res) => {
reject(new Error(`Timeout (${timeoutInMilliseconds}ms) exceeded rendering the component${frame ? ' at frame ' + frame : ' initially'}. ${res.value ? `Open delayRender() handles: ${res.value}` : ''}. You can increase the timeout using the "timeoutInMilliseconds" / "--timeout" option of the function or command you used to trigger this render.`));
})
.catch((newErr) => {
logger_1.Log.warn({ indent, logLevel }, 'Tried to get delayRender() handles for timeout, but could not do so because of', newErr);
// Ignore, use prev error
reject(err);
});
}
else {
reject(err);
}
});
});
const onDisposedPromise = new Promise((_, reject) => {
const onDispose = () => {
reject(new Error('Target closed (page disposed)'));
};
page.on("disposed" /* PageEmittedEvents.Disposed */, onDispose);
cleanups.push(() => {
page.off("disposed" /* PageEmittedEvents.Disposed */, onDispose);
});
});
const onClosedSilentPromise = new Promise((_, reject) => {
const onClosedSilent = () => {
reject(new Error('Target closed'));
};
page.browser.on("closed-silent" /* BrowserEmittedEvents.ClosedSilent */, onClosedSilent);
cleanups.push(() => {
page.browser.off("closed-silent" /* BrowserEmittedEvents.ClosedSilent */, onClosedSilent);
});
});
return Promise.race([
onDisposedPromise,
onClosedSilentPromise,
waitForReadyProm,
]).finally(() => {
cleanups.forEach((cleanup) => {
cleanup();
});
});
};
exports.waitForReady = waitForReady;
const seekToFrame = async ({ frame, page, composition, timeoutInMilliseconds, logLevel, indent, attempt, }) => {
await (0, exports.waitForReady)({
page,
timeoutInMilliseconds,
frame: null,
indent,
logLevel,
});
await (0, puppeteer_evaluate_1.puppeteerEvaluateWithCatchAndTimeout)({
pageFunction: (f, c, a) => {
window.remotion_setFrame(f, c, a);
},
args: [frame, composition, attempt],
frame,
page,
timeoutInMilliseconds,
});
await (0, exports.waitForReady)({ page, timeoutInMilliseconds, frame, indent, logLevel });
await page.evaluateHandle('document.fonts.ready');
};
exports.seekToFrame = seekToFrame;