nanojsx / nano

🎯 SSR first, lightweight 1kB JSX library.
http://nanojsx.io
MIT License
1.45k stars 38 forks source link

[Bug] Hydrate/render recreates server rendered tags in production #66

Closed jrson83 closed 2 years ago

jrson83 commented 2 years ago

Describe the bug This issue can be recreated with nanojsx/template. I found this issue on react-helmet, dealing with the same problem.

When using the nanojsx/template in production, the server side rendered script tag for /public/js/home.hydrate.js gets recreated, when using hydrate/render on the <HomePage /> component.

Steps to recreate:

  1. Install template
  2. Open file ./src/pages/HomePage.tsx
  3. Make changes to the code:
    
    import * as Nano from 'nano-jsx/lib/core'
    import { printVersion } from 'nano-jsx/lib/helpers'
    //import TodoList from '../components/TodoList'
    import { HomePage } from '../pages/HomePage'

const hydrate = async () => { //Nano.hydrate(, document.getElementById('todo-list'))

Nano.render(, document.getElementById('content')) ... }

hydrate()



4. Run `npm run build`
5. Run `npm run serve`
6. Check inspector & console in DevTools

![bug-01](https://user-images.githubusercontent.com/45284565/144096573-eb415b0c-f3e9-455f-90e2-56566b4a7293.PNG)
yandeu commented 2 years ago

This is normal. Inside <HomePage /> it tries to add the file /public/js/home.hydrate.js, which does not exist in production. In production the file has a unique hash.

In my case it loads /public/js/home.hydrate.741d3b9d5a02efd363f6.js (SSR) and then /public/js/home.hydrate.js on the client (does not exist).


In HomePage.tsx you could do:

import Nano, { Helmet } from 'nano-jsx'
import { isSSR } from 'nano-jsx/lib/core'
import MainLayout from '../layouts/MainLayout'
import TodoList from '../components/TodoList'

export const HomePage = (props: any) => {
  return (
    <MainLayout {...props}>
      <Helmet>
        <title>Home Page</title>
      </Helmet>

      {isSSR() ? (
        <Helmet footer>
          <script async src="/public/js/home.hydrate.js"></script>
        </Helmet>
      ) : null}

      <div id="homePage">
        <h1>Home Page</h1>
        <div id="todo-list">
          <TodoList />
        </div>
      </div>
    </MainLayout>
  )
}
jrson83 commented 2 years ago

Great, this is working. Thanks! I tried to wrap inside this, but didn't replace the script at all.

{process.env.NODE_ENV === 'development' &&
  <Helmet footer>
    <script type="text/javascript" async src="/js/client.bundle.js"></script>
  </Helmet>
}