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

React Hot Reload - Styled Component/Emotion #6

Closed
7 tasks done
danieloprado opened this issue Oct 26, 2021 · 16 comments · Fixed by #79
Closed
7 tasks done

React Hot Reload - Styled Component/Emotion #6

danieloprado opened this issue Oct 26, 2021 · 16 comments · Fixed by #79
Labels
bug Something isn't working feat: hmr p3-minor-bug 🔨 An edge case that only affects very specific usage (priority)

Comments

@danieloprado
Copy link

danieloprado commented Oct 26, 2021

Describe the bug

Hot reload won't update the css created by styled, just after a full reload.

Reproduction

Just try to change any css's prop inside a styled:
https://github.com/eduzz/template-react/tree/vite

System Info

System:
    OS: macOS 11.6
    CPU: (4) x64 Intel(R) Core(TM) i5-5350U CPU @ 1.80GHz
    Memory: 490.79 MB / 8.00 GB
    Shell: 5.8 - /bin/zsh
  Binaries:
    Node: 17.0.1 - /usr/local/bin/node
    Yarn: 1.22.17 - /usr/local/bin/yarn
    npm: 8.1.0 - /usr/local/bin/npm
    Watchman: 2021.10.18.00 - /usr/local/bin/watchman
  Browsers:
    Edge: 94.0.992.50
    Safari: 15.0
  npmPackages:
    @vitejs/plugin-react: 1.0.6 => 1.0.6 
    vite: 2.6.11 => 2.6.11

Used Package Manager

yarn

Logs

No response

Validations

@danieloprado
Copy link
Author

Based on this comment I discovery a workaround:

const Component = styled(({ className }) => { // <~ wrap the component here, not in export
 return <div className={className}>hi!</div>
})`
    background: red;
`

This is not a good workaround because it looses the syntax highlighting but it may give some idea how to fix this problem.

@danieloprado
Copy link
Author

danieloprado commented Nov 11, 2021

The real problem is not with styled, is with any HOC.

const Component = ({ className }) => {
 return <div className={className}>hi!</div>
}

const myHOC = (Component, className) => {
 return  (props) => <Component {...props} className={className} />
}

export default myHoc(Component, 'test-class-1') // <~ try to change, no effect.

The Fast Refresh (from react/refresh) only re-run the variable Component (the first capitalized),
if I change the capitalized letters, it worked!

const component = ({ className }) => {
 return <div className={className}>hi!</div>
}

const MyHOC = (Component, className) => {
 return  (props) => <Component {...props} className={className} />
}

export default MyHoc(Component, 'test-class-1') // <~ try to change, no effect.

I don't know if there is any fix for that. 😥

Example:

example.mp4

@danieloprado
Copy link
Author

danieloprado commented Nov 11, 2021

Maybe related to facebook/react#20417 and facebook/react#21104

@gaearon
Copy link

gaearon commented Nov 11, 2021

The Fast Refresh (from react/refresh) only re-run the variable Component (the first capitalized),

That's expected. React component names must always start with a capital letter. This convention is assumed by some other tooling as well so you need to follow it.

@danieloprado
Copy link
Author

@patak-js please reopen we still discussing it haha
@gaearon it was the workaround that I found to try to understand the behaviour.

The problem is with this very common syntax:

const Component =({ className }) => {
 return <div className={className}>hi!</div>
}

export default styled(Component)`
    background-color: red;
`

When you try to change the background-color it does not refresh current value. But when you change the content inside the component (like adding a text), the text is added but the background still the same as before. The fast refresh only refreshes the Component not the styled (or any HOC values)

@patak-dev
Copy link
Member

Does this work with Webpack and not with Vite @danieloprado? Could you create a minimal reproduction that showcases the issue in Vite? Maybe using StackBlitz https://vite.new/react?

@patak-dev patak-dev reopened this Nov 11, 2021
@danieloprado
Copy link
Author

danieloprado commented Nov 11, 2021

Here: https://stackblitz.com/edit/vitejs-vite-k3bzhu?file=src/Test.jsx

Try to change the background-color or try to change the parameter of the TestMyHoc. TestMyHocWorking is an example where refresh is working as expected, I think is because is not a call assignment.

@danieloprado
Copy link
Author

I've just update the code with more examples.

@danieloprado
Copy link
Author

Here an example with rect-sctipts: https://stackblitz.com/edit/react-ptscnt?file=src%2FTest.jsx

@patak-dev patak-dev added the bug Something isn't working label Nov 11, 2021
@oyb81076
Copy link

oyb81076 commented Nov 30, 2021

// Button.tsx
export default function Button(): React.ReactElement | null {
  return (
     <SButton>Text</SButton>
  );
}
const SButton = styled.button`color: green;`;
export const ButtonGroups = styled.button`
color: blue;
`;

当Button和ButtonGroups在一个文件里面的时候,
修改SButton的样式热更新正常,修改ButtonGroups的样式,不会触发热更新.
如果把ButtonGroups 和 Button 拆分到两个文件中,一切都很正常

@crtl
Copy link

crtl commented Oct 29, 2022

I am using a helper function to create and wrap styled function components and it worked using create-react-app but using vite I have to reload for every change.

import {FC} from "react";
import styled from "styled-components";


/**
 * Creates a function component and wraps it in styled-component to enable styling
 * and generates a new displayName for returned component if provided component has one.
 * Usage:
 * ```
 * const MyComponent = createStyledFC<{}>((props) => {
 *     return <div {...props}></div>;
 * })`
 *   background: blue;
 *
 *   .my-styled {
 *       color: red;
 *   }
 * `;
 * ```
 * @param component
 * @param displayName Optional display name for component
 */
export function createStyledFC<T = {}>(component: FC<T & {className?: string}>, displayName?: string) {

    const comp = styled(component as FC<T & {className?: string}>)

    const _displayName = displayName || component.displayName;

    if (_displayName) {
        component.displayName = _displayName;
        (comp as any).displayName = `Styled${_displayName}`;
    }

    return comp;
}

@sapphi-red
Copy link
Member

I confirmed this still does not work. (Vite 4.0.2 + plugin-react 3.0.0)
TestMyHoc.jsx now works but Test.jsx still doesn't work.
https://stackblitz.com/edit/vitejs-vite-gdqpfv?file=package.json,src%2FTestMyHoc.jsx,src%2FTest.jsx

@dominikfucic
Copy link

I was able to reproduce bug.

Create .tsx file and inside create a styled-component with export, and a functional component with default export.

Import both components inside App.tsx, wrap the styled-component with the functional component.

Try changing styles on styled-component.

HMR is not working.

@ZombieChowder11
Copy link

Recently ran into this issue myself and I was wondering if there have been any official updates on this?

@ArnaudBarre
Copy link
Member

It could be fixed by #79
This is using a more precise invalidation algorithm already used in the SWC plugin

@ArnaudBarre
Copy link
Member

Ok just tested the repro and I confirm this is fixing the issue.

Sadly the PR is blocked by a change in esbuild that is shipped with Vite 4. This was fixed two weeks ago and will be included in Vite next minor (currently in beta, so hopefully in less than two weeks).

I will then publish v3.1 with this fix and require Vite 4.1 as a peer dependency.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Something isn't working feat: hmr p3-minor-bug 🔨 An edge case that only affects very specific usage (priority)
Projects
None yet
9 participants