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

the vite's HMR does not work when I use React.lazy() API for lazyload #4298

Closed
6 tasks done
cookiepool opened this issue Jul 18, 2021 · 22 comments · Fixed by #10239
Closed
6 tasks done

the vite's HMR does not work when I use React.lazy() API for lazyload #4298

cookiepool opened this issue Jul 18, 2021 · 22 comments · Fixed by #10239
Labels
bug: upstream Bug in a dependency of Vite

Comments

@cookiepool
Copy link

Describe the bug

when I use React.lazy(),like this:

// router/index.ts
import React from 'react';

const Home = React.lazy(() => import('../views/Home'));
const About = React.lazy(() => import('../views/About'));

const routes = [
  {
    path: '/',
    exact: true,
    component: Home
  },
  {
    path: '/about',
    exact: true,
    component: About
  },
  {
    path: '/login',
    exact: true,
    component: React.lazy(() => import('../views/login/login'))
  },
  {
    path: '/form-page',
    exact: true,
    component: React.lazy(() => import('../views/form-test/form-page'))
  },
  {
    path: '/props-up',
    exact: true,
    component: React.lazy(() => import('../views/form-test/props-up'))
  }
];

export default routes;

supplement!I use react-router-config manage my routes information,like this:

// App.tsx
import { renderRoutes } from 'react-router-config';
import routes from '@/router';

// other code

render(): JSX.Element {
  return (
    <Router>
      <div className={styles.container}>
        <div className={styles['title-wraper']}>
          <Link to="/">
            <span className={styles['link-title']}>Home</span>
          </Link>
          <span className={styles['link-line']}> | </span>
          <Link to="/about">
            <span className={styles['link-title']}>About</span>
          </Link>
        </div>
        <Switch>
          <React.Suspense fallback={<Loading></Loading>}>
            {renderRoutes(routes)}
          </React.Suspense>
        </Switch>
      </div>
    </Router>
  );
}

when I modify some code in Home.tsx or About.tsx etc,the HMR was not effected.I need refresh the broswer can see my modification.

if I dont use React.lazy() API,the HMR is normal!

Reproduction

I see vite HMR can work,but it nonitor a wrong file.
image

image

I modify About.tsx,but vite HMR feed back router/index.ts.

System Info

- OS: win 10
- browser:Chrome 91
- react(react-dom): 17.0.2
- react-router-dom: 5.2.0
- react-router-config: 5.1.1
- vite: 2.4.2

vite.config.ts

import path from 'path';
import { defineConfig } from 'vite';
import reactRefresh from '@vitejs/plugin-react-refresh';
import eslintPlugin from 'vite-plugin-eslint';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [reactRefresh(), eslintPlugin()],
  resolve: {
    alias: { '@': path.join(__dirname, 'src') }
  },
  css: {
    modules: {
      generateScopedName: '[name]__[local]--[hash:base64:5]'
    }
  }
});


### Used Package Manager

npm

### Logs

```shell
no error!

Validations

@y1d7ng
Copy link
Contributor

y1d7ng commented Jul 20, 2021

I can't reproduce this, can you provide a small repro, thanks

@github-actions
Copy link

Hello @cookiepool. Please provide a minimal reproduction using a GitHub repository or codesandbox. Issues marked with need reproduction will be closed if they have no activity within 3 days.

@songzhj
Copy link

songzhj commented Jul 21, 2021

Same issue, My App is like below code:

const A = lazy(() => import('./pages/A'));
const B = lazy(() => import('./pages/B'));

function App() {
  return (
    <HashRouter>
      <Suspense fallback={<div>loading</div>}>
        <Routes>
          <Route path="/a" element={<A />} />
          <Route path="/b" element={<B />} />
        </Routes>
      </Suspense>
    </HashRouter>
  );
}

After use React.lazy, change in Component A (or B) cannot hot reload, but need switch routing.

@y1d7ng
Copy link
Contributor

y1d7ng commented Jul 21, 2021

Same issue, My App is like below code:

const A = lazy(() => import('./pages/A'));
const B = lazy(() => import('./pages/B'));

function App() {
  return (
    <HashRouter>
      <Suspense fallback={<div>loading</div>}>
        <Routes>
          <Route path="/a" element={<A />} />
          <Route path="/b" element={<B />} />
        </Routes>
      </Suspense>
    </HashRouter>
  );
}

After use React.lazy, change in Component A (or B) cannot hot reload, but need switch routing.

in path '/a', change Component B to hot reload?

@npmrun
Copy link

npmrun commented Jul 24, 2021

maybe you can try this:
image
if not add this name, i get the same issue with you.

@cookiepool
Copy link
Author

cookiepool commented Jul 28, 2021

I can't reproduce this, can you provide a small repro, thanks

https://github.com/cookiepool/vite-react-typescript-template you can use this repository!

@harrytran998
Copy link

harrytran998 commented Aug 2, 2021

Hope your team can fix this soon! My team has the same trouble with this!

@cookiepool
Copy link
Author

The issue mainly affects Class Component.Function Component is normal!

@harrytran998
Copy link

The issue mainly affects Class Component.Function Component is normal!

I use Function components, and our app is broken when using lazy import 😅.

@guibwl
Copy link

guibwl commented Aug 2, 2021

I'm using @loadable/component and Function components its worked fine for me.

@SheldonWatson
Copy link

Hope your team can fix this soon! My team has the same trouble with this!

So do I!

@hyf0
Copy link
Contributor

hyf0 commented Aug 14, 2021

https://github.com/iheyunfei/vite-bug-report-4298
I create a reproduction repo. I both using create-react-app and vite to reproduce the problem successfully. So, I guess this is the problem of upstream react-refresh, not vite.

And the problem only happens on function component, Class Component seems to work.

@hyf0
Copy link
Contributor

hyf0 commented Aug 14, 2021

damn. It looks like if you give function component a name, then both c-r-a and vite example works.

     // Anonymous direct exports like export default function() {}
    // are currently ignored.

reference

import React from 'react'
const Foo = () => ( // works
  <div>foo</div>
)
export default Foo
import React from 'react'
export default () => ( // doesn't works
  <div>foo</div>
)

So, It's definitely not a bug of vite, but an intentional behavior of react facebook/react#21181.

@NazimHAli
Copy link

I can't reproduce this either, working examples using lazy throughout the repo https://github.com/NazimHAli/imgur-explorer/blob/master/src/components/App.tsx#L5-L11

@NazimHAli
Copy link

import React from 'react'
const Foo = () => ( // works
  <div>foo</div>
)
export default Foo
import React from 'react'
export default () => ( // doesn't works
  <div>foo</div>
)

So, It's definitely not a bug of vite, but an intentional behavior of react facebook/react#21181.

I think using Foo works because component names have to start with a capital letter: https://reactjs.org/docs/components-and-props.html

Note: Always start component names with a capital letter.
React treats components starting with lowercase letters as DOM tags. For example,

represents an HTML div tag, but represents a component and requires Welcome to be in scope.

@nanslee
Copy link

nanslee commented Oct 28, 2021

The issue mainly affects Class Component.Function Component is normal!

I use Function components, and our app is broken when using lazy import 😅.

Have you solve the problem? How to do ?

@RubenLaube-Pohto
Copy link

So, if I understood correctly, a named export works but a default export won't? Does wrapping a component with lazy forget about the naming? I have a setup like this and I'm having trouble with HMR:

// MyComponent.tsx
export const MyComponent: React.FunctionComponent

// App.tsx
const MyComponent = React.lazy(() => import('./components/MyComponent').then(
  res => ({ default: res.MyComponent })
)

const App = () => {
  return (
    <Route path='/' component={MyComponent} />
  )
}

Is there some other way I could try to get HMR working correctly?

@NazimHAli
Copy link

NazimHAli commented Oct 28, 2021

So, if I understood correctly, a named export works but a default export won't? Does wrapping a component with lazy forget about the naming? I have a setup like this and I'm having trouble with HMR:

Default exports work - working example:

https://github.com/NazimHAli/imgur-explorer/blob/master/src/components/App.tsx#L5-L13

const Explore = lazy(() => import("@/components/Explore"));
const Footer = lazy(() => import("@/components/Footer"));
const Header = lazy(() => import("@/components/Header"));
const ImageGrid = lazy(() => import("@/components/ImageGrid"));

@RubenLaube-Pohto
Copy link

I see... Well, my setup is a bit more complex with routing, custom providers and hooks. In a nutshell, when HMR is triggered for a component in the lazy loaded path, a hook fails to get a parameter from the URL. It just returns a default value I've set without actually checking the URL again.

If I find the time, I'll try making a small reproduction.

@NazimHAli
Copy link

@RubenLaube-Pohto that would make it easier to help troubleshoot 👍

@oller
Copy link

oller commented Jul 6, 2022

I'm encountering this issue and can't find any obvious places where i'm not defining a component as a const before export defaulting it.

Any additional input on how people got over this would be appreciated!

@zqinmiao
Copy link

zqinmiao commented Sep 5, 2022

I'm using @loadable/component and Function components its worked fine for me.

@guibwl
After i used @loadable/component, it works fine。Thank

@github-actions github-actions bot locked and limited conversation to collaborators Oct 20, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug: upstream Bug in a dependency of Vite
Projects
None yet
Development

Successfully merging a pull request may close this issue.