lexical icon indicating copy to clipboard operation
lexical copied to clipboard

Can't use `generateHtmlFromNodes` correctly for SSR

Open eashish93 opened this issue 2 years ago • 10 comments

When using generateHtmlFromNodes, I encountered an error: To use $generateHtmlFromNodes in headless mode please initialize a headless browser implementation such as JSDom before calling this function. which is fine as JSDOM is required, but this error doesn't mention which variables this function needs, so I dig into the code and found that we need to declare something like this first to make it work:

const { JSDOM } = jsdom;

const window = new JSDOM(`...`).window;
global.document = window.document;
// @ts-expect-error
global.window = window;

// Sometimes `global.navigator` also needs to be defined with `global.window `

// @ts-expect-error
global.DocumentFragment = function() { return JSDOM.fragment(``) }

This function is checking for both document and window. This should only check for document and DocumentFragment only, as these are the only methods generateHtmlFromNodes using.

Lexical version: 0.7.4

eashish93 avatar Dec 22 '22 03:12 eashish93

Same issue here. Overriding document, window etc. also seems to trip up NextJS's API runtime, so an option to pass in JSDOM as an override would be amazing.

Multiply avatar Dec 29 '22 21:12 Multiply

Same issue here. Overriding document, window etc. also seems to trip up NextJS's API runtime, so an option to pass in JSDOM as an override would be amazing.

@thegreatercurve @zurfyx any plan to add this? Would avoid polluting the backend environment as mentioned in https://github.com/facebook/lexical/issues/3097#issuecomment-1511496254

sneko avatar Apr 17 '23 14:04 sneko

I also just stumbled over this. For context: I'm persisting the editor's collaboration state in form of the Ydoc using Hocuspocus and a custom persistence extension. On the server-side I'm storing/loading the Ydoc, and in addition I want to generate HTML from the Ydoc / editorstate so that I can server-side render an HTML preview of the editor before it's fully loaded.

Bunkerbewohner avatar May 01 '23 21:05 Bunkerbewohner

~I can't even get the JSDOM solution to work, happy to get an example to look at if anyone can share!~

Nevermind, using Next and it makes it go bonkers

Fritiof avatar Sep 21 '23 20:09 Fritiof

I also just stumbled over this. For context: I'm persisting the editor's collaboration state in form of the Ydoc using Hocuspocus and a custom persistence extension. On the server-side I'm storing/loading the Ydoc, and in addition I want to generate HTML from the Ydoc / editorstate so that I can server-side render an HTML preview of the editor before it's fully loaded.

You can create a webpack library in a nodejs workspace and have the document and window properties defined globally there or utilize webpack's webpack.ProvidePlugin plugin Wrote a solution about it here

Chigozie-Gerald avatar Mar 24 '24 21:03 Chigozie-Gerald

This implementation solves the issue for Next

konhi avatar Feb 16 '25 15:02 konhi

This implementation solves the issue for Next

But other concurrent requests might fail while this function is running because this is still polluting global??

koderyoda avatar Feb 28 '25 05:02 koderyoda

No, it’s all synchronous, there’s no danger of polluting other requests assuming your finalizer is correct.

etrepum avatar Feb 28 '25 06:02 etrepum

I noticed without the finalizer block, it wiped my environment variables for subsequent unrelated requests. The finalizer fixed that. But I am guessing in prod this means that requests will (seem to) arbitrarily fail if they coincide with any other request running this function.

koderyoda avatar Feb 28 '25 06:02 koderyoda

No. This function runs synchronously, no other code can execute while it is running. JavaScript doesn’t have any parallelism.

etrepum avatar Feb 28 '25 13:02 etrepum