Skip to content
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

How to render !doctype and comment nodes (Preact X) #1469

Closed
katyo opened this issue Mar 28, 2019 · 1 comment
Closed

How to render !doctype and comment nodes (Preact X) #1469

katyo opened this issue Mar 28, 2019 · 1 comment

Comments

@katyo
Copy link
Contributor

katyo commented Mar 28, 2019

I trying to create document-wide isomorphic app.

The root component looks like:

function Main(props: Props) {
    // ....
    return h("html", null,
             h("head", null,
               // ....
             h("body", null,
               // ....
              )
            );
}

Because I don't know how to create !DOCTYPE node when rendering I simply prepend this as string to the rendered html on server side.

But it causing the problem on client: Uncaught DOMException: Failed to execute 'insertBefore' on 'Node': Can't insert an element before a doctype.

My client side looks like:

hydrate(h(Main, { /* ... */ }), document);

When I try to rehydrate using document.documentElement instead of document, it adds second html node instead of reusing existing.

When I remove !DOCTYPE node on server side it works as expected.

It seems the first doctype node should be created by root render itself for correct rehydration.

How can I create !DOCTYPE node (and html comment nodes <!-- ... -->) when rendering?

@marvinhagemeister
Copy link
Member

Rendering anything outside of document.body on the client is not well supported in any framework. In particular changing the doctype will have no effect as the browser won't have any effect because they won't re-evaluate the document. Another problem may arise when CDNs or even browser extensions modify the <head> section by adding custom snippets or rewriting urls.

To make it short: Rendering anything directly via any SPA-Framework outside of <body> leads to a whole class of problems. A much better solution for SSR is to only render the app and put the result in a predefined html template.

// server.js
import App from "./myapp";
import { render } from "preact-render-to-string";

const app = render(<App />);

const html = `
<!DOCTYPE html>
<html>
<head>...</head>
<body>
  <div id="root">${app}</div>
  <script src="my-bundle.js"></script>
</html>
`;

If you need to change anything inside <head> once you are on the client, the only safe way is to mutate it yourself via the DOM api. There is a nice abstraction in the form of a react component called react-helmet which hides that from you.

Regarding your second question about comment nodes: They can only be rendered via document.createComment(). There is no built-in way to render them as they are typically removed in production to reduce the total size of the html that needs to be send to the client. You could wrap the above function in a component if you absolutely need a way to render html comments from Preact.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants