-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Hydration Issues #5
Comments
I'm facing this issue you describing here @mayerraphael , have any progress or updates been done so that we can get around this problem? I really appreciate any help |
@halodevcr there is. just run defineCustomElements not inside a react component (like he does in _app.tsx) but add it as an custom script tag to head so it runs before nextjs hydrates. stencil will rewrite the components back to their shadow dom form and react stops complaining as the fiber matches the dom again. if you dont get it working just write me again. i can create a working sample. |
I would highly appreciate the working sample @mayerraphael , I have replicated the whole thing locally but I'm still getting the "Error: Hydration failed because the initial UI does not match what was rendered on the server." Could the latest version of next be the issue ? I noticed this example is using 12 and mine 13 |
@halodevcr The problem with components without Shadow DOM is that they are rendered by the Hydrate package, but the internal DOM of the component is never hidden once stencil hydrates, as there is no shadow dom. So there is a break between what you specified in your NextJS/React component and what exists after stencil renders. Also keep in mind that stencil adds the Get it workingFirst i upgraded NextJS and React to the latest version according to https://nextjs.org/docs/upgrading
import { useState } from 'react';
import {
ShadowExample,
SlotShadowExample,
} from 'component-library-react';
const Index = () => {
const [counter, setCounter] = useState(0);
return (
<div className="hero">
<h1 className="title">Next.js + Tailwind</h1>
<div>
<h2>{counter}</h2>
<button onClick={() => setCounter(counter + 1)}>Increment</button>
</div>
<h4>slot-shadow-example</h4>
<SlotShadowExample>
<div onClick={console.log}>-SLOT CONTENT-</div>
</SlotShadowExample>
<hr />
<h4>shadow-example</h4>
<ShadowExample first="Jag" last="Reehal"></ShadowExample>
</div>
);
};
export default Index; When i start the example, i get the following ERROR So we need to adjust two files.
const express = require("express");
const { createServer } = require('http');
const { parse } = require('url');
const next = require('next');
const hydrate = require('component-library/hydrate');
const dev = process.env.NODE_ENV !== 'production';
const hostname = 'localhost';
const port = process.env.PORT || 5001;
// when using middleware `hostname` and `port` must be provided below
const app = next({ dev, hostname, port });
const handle = app.getRequestHandler();
app.prepare().then(() => {
const server = express();
server.use(function(req, _, next) {
req.url = req.originalUrl.replace('/nextjs_custom_server/_next', '/_next');
console.log(req.url)
next(); // be sure to let the next middleware handle the modified request.
});
server.use("/assets/components", express.static("./node_modules/component-library"));
server.get('/__nextjs_original-stack-frame', (req, res) => {
handle(req, res);
});
server.get('/_next/*', (req, res) => {
handle(req, res);
});
server.all('*', async (req, res) => {
const parsedUrl = parse(req.url, true);
const { pathname, query } = parsedUrl;
const html = await app.renderToHTML(req, res, pathname, query);
const renderedHtml = await hydrate.renderToString(html);
res.end(renderedHtml.html);
})
server.listen(port, (err) => {
if (err) throw err;
console.log(`> Ready on http://${hostname}:${port}`);
});
}) And the new import { Html, Head, Main, NextScript } from 'next/document'
import Script from 'next/script'
export default function Document() {
return (
<Html lang="en">
<Head>
<Script type="module" strategy="beforeInteractive">
{`
import { defineCustomElements } from "/assets/components/loader/index.js";
console.log("Hydrate stencil");
defineCustomElements(window).then(() => console.log("done"));
`}
</Script>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
} The result is a working example (without an hydration error, only a warning which we cannot resolve yet and it does not have any affect on anything). The WebComponent was rendered successfully. If you also want better SSR support with Stencil, please upvote my feature request at stencil: ionic-team/stencil#4010 |
This example works only in shadow dom components? I have the same problem, I tried your solution but not working in scoped components ( light dom ) using stencil as web components. |
Literally the first sentences says that it only works with shadow dom components, as they are resolved to fragments which do not conflict with reacts' fibers. |
This is known with WebComponents and any form of hydration.
StencilJS hydrate removes the Slot Elements and places them inside the component and renders them.
Now in your NextJS page, you have the old
<SlotExample>-SLOT CONTENT-</SlotExample>
tag.So it does not match when NextJS is hydrating the WebComponent.
Currently there is no way around that problem. You maybe just don't get the error message because of the PRODUCTION env.
The text was updated successfully, but these errors were encountered: