2022-09-02 19:49:06 -06:00
'use strict' ;
// Server-side render Hydrogen to a string.
//
// We use a `child_process` because we want to be able to exit the process after
// we receive the SSR results. We don't want Hydrogen to keep running after we
// get our initial rendered HTML.
const assert = require ( 'assert' ) ;
2023-05-01 23:39:01 -06:00
const RethrownError = require ( '../lib/errors/rethrown-error' ) ;
const RouteTimeoutAbortError = require ( '../lib/errors/route-timeout-abort-error' ) ;
const UserClosedConnectionAbortError = require ( '../lib/errors/user-closed-connection-abort-error' ) ;
2022-09-02 19:49:06 -06:00
const runInChildProcess = require ( '../child-process-runner/run-in-child-process' ) ;
2023-04-24 23:50:43 -06:00
const resolvedRenderHydrogenToStringUnsafeScriptPath = require . resolve (
'./render-hydrogen-to-string-unsafe'
) ;
2022-09-02 19:49:06 -06:00
// The render should be fast. If it's taking more than 5 seconds, something has
// gone really wrong.
const RENDER _TIMEOUT = 5000 ;
2023-05-01 23:39:01 -06:00
async function renderHydrogenToString ( { renderOptions , abortSignal } ) {
2022-10-19 11:07:39 -06:00
assert ( renderOptions ) ;
2022-09-02 19:49:06 -06:00
2022-10-18 01:40:40 -06:00
// We expect `config` but we should sanity check that we aren't leaking the access token
// to the client if someone naievely copied the whole `config` object to here.
assert ( renderOptions . vmRenderContext . config ) ;
assert (
! renderOptions . vmRenderContext . config . matrixAccessToken ,
'We should not be leaking the `config.matrixAccessToken` to the Hydrogen render function because this will reach the client!'
) ;
2022-09-02 19:49:06 -06:00
try {
// In development, if you're running into a hard to track down error with
// the render hydrogen stack and fighting against the multiple layers of
// complexity with `child_process `and `vm`; you can get away with removing
// the `child_process` part of it by using
// `render-hydrogen-to-string-unsafe` directly.
// ```js
// const _renderHydrogenToStringUnsafe = require('../hydrogen-render/render-hydrogen-to-string-unsafe');
// const hydrogenHtmlOutput = await _renderHydrogenToStringUnsafe(renderOptions);
// ```
//
// We use a child_process because we want to be able to exit the process after
// we receive the SSR results. We don't want Hydrogen to keep running after we
// get our initial rendered HTML.
const hydrogenHtmlOutput = await runInChildProcess (
2023-04-24 23:50:43 -06:00
resolvedRenderHydrogenToStringUnsafeScriptPath ,
2022-09-02 19:49:06 -06:00
renderOptions ,
{
timeout : RENDER _TIMEOUT ,
2023-05-01 23:39:01 -06:00
abortSignal ,
2022-09-02 19:49:06 -06:00
}
) ;
return hydrogenHtmlOutput ;
} catch ( err ) {
2023-05-01 23:39:01 -06:00
// No need to wrap these errors since the abort originates from outside of the
// render process. And makes it easier to detect without having to look for
// underlying causes.
if ( err instanceof RouteTimeoutAbortError || err instanceof UserClosedConnectionAbortError ) {
throw err ;
} else {
throw new RethrownError (
` Failed to render Hydrogen to string. In order to reproduce, feed in these arguments into \` renderHydrogenToString(...) \` : \n renderHydrogenToString arguments: ${ JSON . stringify (
renderOptions
) } ` ,
err
) ;
}
2022-09-02 19:49:06 -06:00
}
}
module . exports = renderHydrogenToString ;