Description
I was trying to use react-router, preact and preact-ssr-prepass together and ran into some issues. After eliminating an unrelated ESM/CJS error, I discovered that I was still running into issues with preact-ssr-prepass. It turns out it can be reproduced with a pretty short example:
import 'preact/debug'; // if you comment this line out, it will work
import { h } from 'preact';
import renderToString from 'preact-render-to-string';
import prepass from 'preact-ssr-prepass';
import { useState } from 'preact/hooks';
const App = () => {
const [x, setX] = useState(10);
console.log(`Use state inside of App`, x);
return h('div', undefined, x);
};
const vnode = h(App);
console.log('begin prepass');
await prepass(vnode);
console.log('end prepass');
const out = renderToString(vnode);
console.log(out);
Output:
❯ node index.js
begin prepass
Error: Hook can only be invoked from render methods.
at async ESMLoader.import (https://node-qpdrhr-230n5kih.w.staticblitz.com/blitz.f2b7d4e326e0543f39833cc6d890b02bb01d7899.js:6:1209283)
at async i.loadESM (https://node-qpdrhr-230n5kih.w.staticblitz.com/blitz.f2b7d4e326e0543f39833cc6d890b02bb01d7899.js:6:246622)
at async handleMainPromise (https://node-qpdrhr-230n5kih.w.staticblitz.com/blitz.f2b7d4e326e0543f39833cc6d890b02bb01d7899.js:6:989292)
Here is a stackblitz: https://stackblitz.com/edit/node-qpdrhr?file=index.js
Basically as far as I can tell preact/debug
is throwing an error because when the useState()
hook is called, hooksAllowed is false. I guess this is related to the timing of the component lifecycle. I think the error from preact/debug
seems mistaken because when I comment out that preact/debug
import any code I write seems to work fine.
I wonder if this will be fixed by #47? Because it seems that options._diff
function will set hooksAllowed = true
.
The obvious solution may be to "not use preact/debug on the server side", which I think makes sense. But, in my case I was trying to set up an SSR project with @preact/preset-vite, which has the preact/debug
hardcoded in so I never had a choice or knew it was being imported. I'm going to see if I can override it and skip the preact/debug
import for the server side render.