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

Doesn't work with Vite + React #243

Closed
Vexcited opened this issue Apr 12, 2022 · 24 comments
Closed

Doesn't work with Vite + React #243

Vexcited opened this issue Apr 12, 2022 · 24 comments
Labels
more info required question Further information is requested

Comments

@Vexcited
Copy link

Hello ! I'm currently having troubles trying to use this library with my React project.

This is my wdyr.ts file:

/// <reference types="@welldone-software/why-did-you-render" />
import React from "react";

export default async function load () {
  if (process.env.NODE_ENV === "development") {
    // Importing because we can't require in Vite.
    const { default: whyDidYouRender } = await import("@welldone-software/why-did-you-render");

    whyDidYouRender(React, {
      trackAllPureComponents: true,
    });
  }
}

This is how I integrate it in my main.tsx (mountpoint)

import wdyr from "./wdyr";
await wdyr();

import React from "react";
import ReactDOM from "react-dom";

ReactDOM.render(
  <React.StrictMode>
    <AppRoutingAndMoreRightHere />
  </React.StrictMode>,
  document.getElementById("root")
);

When I run it, there isn't any errors, but still it doesn't work.
I've also tried to add MyComponent.whyDidYouRender = true; but still have no effect.

By the way, I'm using vite 2.7.13 and react 17.0.2.

Hope you can help me with this !

@vzaidman
Copy link
Collaborator

Why is this async?
It won't work because it needs to happen in the first thread of the application. Once you make it async, it moves to the next thread.
Try that and tell me if it helps.

@vzaidman vzaidman added question Further information is requested more info required labels Apr 18, 2022
@Vexcited
Copy link
Author

The thing is that even without async it still doesn't work ~

I made here a StackBlitz example with a blank project.
https://stackblitz.com/edit/vitejs-vite-kyrupm?file=src/main.tsx

See main.tsx and wdyr.ts.

@jdnarvaez
Copy link

I was able to get this working with vite by using the following

wydr.ts

import React from 'react';
import whyDidYouRender from '@welldone-software/why-did-you-render';

if (process.env.NODE_ENV === 'development') {
  whyDidYouRender(React, {
    trackAllPureComponents: true,
  });
}

main.tsx

import './wdyr';
import React from 'react'
.
.
.

Then setting MyFunctionalComponent.whyDidYouRender = true

@Vexcited
Copy link
Author

Vexcited commented Apr 28, 2022

Uhm, I'm sorry but I still can't get it to work with

main.tsx

import './wdyr';
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import './index.css';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

wdyr.ts

/// <reference types="@welldone-software/why-did-you-render" />
import React from 'react';
import whyDidYouRender from '@welldone-software/why-did-you-render';

if (process.env.NODE_ENV === 'development') {
  whyDidYouRender(React, {
    trackAllPureComponents: true,
  });
}

App.tsx

function App() {
  return (<div>/** some code */</div>);
}

App.whyDidYouRender = true;
export default App;

There's still nothing in my console
image

@jdnarvaez
Copy link

I played around a little bit with your sandbox and I, too, could not get it to work. Might be something with our configs, but what we have setup at my work seems to work with this tool.

@Vexcited
Copy link
Author

Hope we could find a workaround because I think that this tool can really help me in some of my projects for debugging.

Anyway, I'll try to find more informations on my own about this issue. If I find anything useful, I'll comment it here.

@jdnarvaez
Copy link

this also seems to work

  const { default: whyDidYouRender } = await import('@welldone-software/why-did-you-render');

  whyDidYouRender(React, {
    logOnDifferentValues: true,
    trackAllPureComponents: true,
  });

for purposes of keeping it a dev dependency. I am not quite sure why it does not work in the example you posted above.

@vzaidman
Copy link
Collaborator

vzaidman commented Apr 28, 2022

@jdnarvaez wait so does it works or not? ;O

this also seems to work
I would not expect that anything with "await" would work, because it means that the code would be applied in the next browser thread cycle.

@jdnarvaez
Copy link

@jdnarvaez wait so does it works or not? ;O

this also seems to work
I would not expect that anything with "await" would work, because it means that the code would be applied in the next browser thread cycle.

It works fine for me in my local project, it does not seem to work on the sandbox that is linked above.

@Vexcited
Copy link
Author

and also doesn't work in my Vite projects (made with yarn create vite and react-ts option)

@anatoliykot
Copy link

Doesn't work for me as well

@anatoliykot
Copy link

anatoliykot commented May 20, 2022

Solution:
vite.config.ts

export default defineConfig({
  plugins: [
    checker({ typescript: true }),
    svgr(),
    react({
      jsxImportSource: '@welldone-software/why-did-you-render', // <-----
    }),
  ],
  resolve: {
    alias: {
      // Needed for `useSelector` tracking in wdyr.tsx: https://github.com/welldone-software/why-did-you-render/issues/85
      'react-redux': 'react-redux/dist/react-redux.js',
    },
  },
});

wdyr.ts

/// <reference types="@welldone-software/why-did-you-render" />
import * as React from 'react';
import * as ReactRedux from 'react-redux';
import whyDidYouRender from '@welldone-software/why-did-you-render';

if (import.meta.env.DEV) {
  whyDidYouRender(React, {
    trackAllPureComponents: true,
    trackExtraHooks: [[ReactRedux, 'useSelector']],
  });
}

@Vexcited
Copy link
Author

Sorry for the late response but the solution from @anatoliykot seems to work for me so I'll close this issue !

Thanks you for your help !

@jensbodal
Copy link

Thanks for proposing a solution, a few questions:

  1. > /// <reference types="@welldone-software/why-did-you-render" />
    Why do you need to import types like this if you’re already using typescript?
  2. What is the purpose of jsxImportSource? This seems to be working without it.
  3. Where are you importing the wdyr.ts file?

@jensbodal
Copy link

jensbodal commented Jul 11, 2022

What’s working for me is the following

wdyr.ts

import * as React from 'react';

if (import.meta.env.DEV && import.meta.env.VITE_ENABLE_WHY_DID_YOU_RENDER === 'true') {
  const { default: wdyr } = await import('@welldone-software/why-did-you-render');

  wdyr(React, {
    include: [/.*/],
    exclude: [/^BrowserRouter/, /^Link/, /^Route/],
    trackHooks: true,
    trackAllPureComponents: true,
  });
}

main.tsx

// eslint-disable-next-line import/order
import './wdyr';

...

const root = createRoot(container);
root.render( ...

tsconfig.json

    "module": "ES2022",
    "target": "ES2017"

Despite using the above module/target browserlist provides a prod build time check to ensure I’m still using compatible features (aka I can’t ship code that’s using top-level await but I can use them behind a dev flag)

No trace of wdyr in the build output and works locally with the flag enabled.

@mwskwong
Copy link

What’s working for me is the following

wdyr.ts

import * as React from 'react';

if (import.meta.env.DEV && import.meta.env.VITE_ENABLE_WHY_DID_YOU_RENDER === 'true') {
  const { default: wdyr } = await import('@welldone-software/why-did-you-render');

  wdyr(React, {
    include: [/.*/],
    exclude: [/^BrowserRouter/, /^Link/, /^Route/],
    trackHooks: true,
    trackAllPureComponents: true,
  });
}

main.tsx

// eslint-disable-next-line import/order
import './wdyr';

...

const root = createRoot(container);
root.render( ...

tsconfig.json

    "module": "ES2022",
    "target": "ES2017"

Despite using the above module/target browserlist provides a prod build time check to ensure I’m still using compatible features (aka I can’t ship code that’s using top-level await but I can use them behind a dev flag)

No trace of wdyr in the build output and works locally with the flag enabled.

Why is this marked as a solution? It imports why-did-you-render regardless of the environment it is in. It will include why-did-you-render in the production bundle.

@jensbodal
Copy link

jensbodal commented Jul 14, 2022

Why is this marked as a solution? It imports why-did-you-render regardless of the environment it is in. It will include why-did-you-render in the production bundle.

... it does not include it in the production bundle

if (import.meta.env.DEV && import.meta.env.VITE_ENABLE_WHY_DID_YOU_RENDER === 'true') {

This line is statically analyzed and everything below it is omitted from the production bundle (if the condition is false), meaning why-did-you-render is not in the production bundle.

This also allows a user to turn it on or off locally by flipping an environment variable for VITE_ENABLE_WHY_DID_YOU_RENDER.

This is verified by reviewing the production bundle with and without these flags set, and also verifying the production bundle size is the exact same before and after this change.

@mwskwong
Copy link

mwskwong commented Jul 14, 2022

Why is this marked as a solution? It imports why-did-you-render regardless of the environment it is in. It will include why-did-you-render in the production bundle.

... it does not include it in the production bundle

if (import.meta.env.DEV && import.meta.env.VITE_ENABLE_WHY_DID_YOU_RENDER === 'true') {

This line is statically analyzed and everything below it is omitted from the production bundle (if the condition is false), meaning why-did-you-render is not in the production bundle.

This also allows a user to turn it on or off locally by flipping an environment variable for VITE_ENABLE_WHY_DID_YOU_RENDER.

This is verified by reviewing the production bundle with and without these flags set, and also verifying the production bundle size is the exact same before and after this change.

Damn, I meant to quote @anatoliykot's post. For his case, it does include that in PROD. And yes, yours doesn't. But in certain instances, WDYR may be initialized too late because of the dynamic import. e.g. Your answer will not work in Gatsby.

@jensbodal
Copy link

Yeah I think the only way around that is to just leave import './wdyr.ts' commented out (and not having it use dynamic import) then commenting it back in when you need it.

For just vite+react I saw no difference between the two so I left it as I have it.

@mwskwong
Copy link

Yeah I think the only way around that is to just leave import './wdyr.ts' commented out (and not having it use dynamic import) then commenting it back in when you need it.

For just vite+react I saw no difference between the two so I left it as I have it.

I find the safest way is to simply use require and tell ESLint to ignore the checking on wdyr.ts.

@jensbodal
Copy link

jensbodal commented Jul 14, 2022

Edit: globEager cannot be used conditionally like I have it below, so for vite purposes my first example is still what we are using.


So it looks like instead we can leverage vite’s globEager (docs appear out of date since globEager is mentioned there as an option) usage to have this do what we want. We cannot use require with vite, and this issue is specific to vite.

main.tsx

/* eslint-disable import/first */
if (import.meta.env.DEV && import.meta.env.VITE_ENABLE_WHY_DID_YOU_RENDER === 'true') {
  // eslint-disable-next-line @typescript-eslint/no-unused-vars, unused-imports/no-unused-vars
  const autoImport = import.meta.globEager('./wdyr.ts'); 
  // nothing needs to be done with this variable but one needs to be declared in order to import the module
}

wdyr.ts

import wdyr from '@welldone-software/why-did-you-render';
import * as React from 'react';

wdyr(React, {
  include: [/.*/],
  exclude: [/^BrowserRouter/, /^Link/, /^Route/],
  trackHooks: true,
  trackAllPureComponents: true,
});

That said, I believe that my original suggestion still works the same since the import './wdyr' line will be converted to a static require with vite, and then the import of wdyr should be completed synchronously before the rest of the code.

@angelitolm
Copy link

import * as React from 'react';
import * as ReactDOM from 'react-dom/client';
import App from './App';
import './index.css';

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>

</React.StrictMode>
);

@vzaidman
Copy link
Collaborator

vzaidman commented Jan 7, 2023

import * as React from 'react'; import * as ReactDOM from 'react-dom/client'; import App from './App'; import './index.css';

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( <React.StrictMode> </React.StrictMode> );

where is the WDYR import?

@gkatsanos
Copy link

gkatsanos commented Feb 13, 2023

this actually worked. @vzaidman could we add this to the documentation? PR's welcome?

What’s working for me is the following

wdyr.ts

import * as React from 'react';

if (import.meta.env.DEV && import.meta.env.VITE_ENABLE_WHY_DID_YOU_RENDER === 'true') {
  const { default: wdyr } = await import('@welldone-software/why-did-you-render');

  wdyr(React, {
    include: [/.*/],
    exclude: [/^BrowserRouter/, /^Link/, /^Route/],
    trackHooks: true,
    trackAllPureComponents: true,
  });
}

main.tsx

// eslint-disable-next-line import/order
import './wdyr';

...

const root = createRoot(container);
root.render( ...

tsconfig.json

    "module": "ES2022",
    "target": "ES2017"

Despite using the above module/target browserlist provides a prod build time check to ensure I’m still using compatible features (aka I can’t ship code that’s using top-level await but I can use them behind a dev flag)

No trace of wdyr in the build output and works locally with the flag enabled.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
more info required question Further information is requested
Projects
None yet
Development

No branches or pull requests

8 participants