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

ESM support #3882

Closed
TkDodo opened this issue Jul 20, 2022 · 33 comments · Fixed by #3892 or #4092
Closed

ESM support #3882

TkDodo opened this issue Jul 20, 2022 · 33 comments · Fixed by #3892 or #4092
Labels
enhancement New feature or request esm

Comments

@TkDodo
Copy link
Collaborator

TkDodo commented Jul 20, 2022

we had it in v4 beta, but it went away with the rebranding.

prior art:

there were some useSyncExternalStore issues reported after that, which prompted another fix:

@TkDodo TkDodo added the enhancement New feature or request label Jul 20, 2022
@TkDodo
Copy link
Collaborator Author

TkDodo commented Jul 20, 2022

@sachinraja FYI

@TkDodo
Copy link
Collaborator Author

TkDodo commented Aug 11, 2022

let's try to keep discussion about ESM support here :)

I tried out 4.0.11-beta.0 and it works fine in our simple example, but that one uses vite:

There have been reports on discord that this version "breaks the app", but we'd need more info and try out more bundlers I guess.

cc @DamianOsipiuk

@sachinraja
Copy link
Contributor

@TkDodo Yeah if they share reproductions or at least error messages, I can look into it.

@TkDodo
Copy link
Collaborator Author

TkDodo commented Aug 12, 2022

@sachinraja I can confirm that 4.0.11-beta.0 doesn't work with react-scripts v4. Here is an (older) repo of mine that uses v4 of react-scripts, and I've merely switched from 4.1.0 where it works (but doesn't render devtools at all as per the issue) to the beta:

what I'm seeing when I run it is this:

Screenshot 2022-08-12 at 20 06 57

I can also confirm that removing the rendering of the <ReactQueryDevtools initialIsOpen /> makes the error go away.

@TkDodo
Copy link
Collaborator Author

TkDodo commented Aug 12, 2022

Another thing I found out with @DamianOsipiuk is that the size of the beta is 5x times too large:

https://bundlephobia.com/package/@tanstack/react-query@4.0.11-beta.0

I think @DamianOsipiuk mentioned that react-dom is included because it wasn't specified as external. Just wanted to note all known issues here :)

@sachinraja
Copy link
Contributor

sachinraja commented Aug 12, 2022

I've seen that Provider error before, it has to do with bundlers picking the cjs format for one package and the same format for the other package.

@TkDodo TkDodo added the esm label Aug 13, 2022
@TkDodo
Copy link
Collaborator Author

TkDodo commented Aug 18, 2022

@DamianOsipiuk I tried the latest beta (4.0.11-beta.4) with react-scripts v4 and it now fails with:

Screenshot 2022-08-18 at 14 06 25

Failed to compile.

./node_modules/@tanstack/react-query-devtools/build/lib/index.mjs
Can't import the named export 'Fragment' from non EcmaScript module (only default export is available)

@DamianOsipiuk
Copy link
Contributor

Hmm it seems that it now complains about esm + cjs interop. At least it's picking up correct entry right now.
Will take a look at that.

@DamianOsipiuk
Copy link
Contributor

So far when i have played with it i was unable to make it work for webpack 4 while maintaining support for other bundlers.

There is additional config needed for webpack 4 to make it work, which will be a pain for react-scripts users due to webpack config being inaccessible without third party tools.

I have one more idea which i will test when i will have some time, via exports.node.

All other ideas to solve this problem appreciated.

@TkDodo
Copy link
Collaborator Author

TkDodo commented Aug 23, 2022

can I ask all interested parties to please try out the latest and greatest beta version:

https://github.com/TanStack/query/releases/tag/v4.3.0-beta.3

on my create-react-app v4, I see no problems now:

  • app works in dev mode
  • devtools show up
  • devtools are stripped from production builds 🎉

@TkDodo
Copy link
Collaborator Author

TkDodo commented Aug 23, 2022

One thing that doesn't work is the lazy import of the devtools in production. looking at our exports, there should be a .production entry point:

"exports": {
".": {
"development": {
"types": "./build/lib/index.d.ts",
"import": "./build/lib/index.mjs",
"default": "./build/lib/index.js"
},
"default": {
"types": "./build/lib/index.d.ts",
"import": "./build/lib/noop.mjs",
"default": "./cjs.fallback.js"
}
},
"./production": {
"types": "./build/lib/index.d.ts",
"import": "./build/lib/index.mjs",
"default": "./build/lib/index.js"
},
"./package.json": "./package.json"
},

However, if I'm trying:

const ReactQueryDevtoolsProduction = React.lazy(() =>
    import('@tanstack/react-query-devtools/production').then(d => ({
        default: d.ReactQueryDevtools,
    }))
)

I'm getting the error:

TS2307: Cannot find module '@tanstack/react-query-devtools/production' or its corresponding type declarations.
     7 |
     8 | const ReactQueryDevtoolsProduction = React.lazy(() =>
  >  9 |     import('@tanstack/react-query-devtools/production').then(d => ({
       |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    10 |         default: d.ReactQueryDevtools,
    11 |     }))
    12 | )

I tried this with create-react-app v4 and v5

@TkDodo
Copy link
Collaborator Author

TkDodo commented Aug 23, 2022

I also tried out our nextJs example and it works fine with the beta:

https://codesandbox.io/s/recursing-wind-vo3htt

@TkDodo
Copy link
Collaborator Author

TkDodo commented Aug 23, 2022

okay one more tiny thing:
it seems that direct dependencies of the devtools are now included in the production bundle:

https://unpkg.com/@tanstack/react-query-devtools@4.3.0-beta.3/build/umd/index.production.js

I can see useSyncExternalStore and match-sorter-utils being bundled.

this is also visible in bundlephobia:
https://bundlephobia.com/package/@tanstack/react-query-devtools@4.3.0-beta.3

Screenshot 2022-08-23 at 10 22 48

4.2.1 has 317B while 4.3.0-beta.3 has 8.2kB

@DamianOsipiuk
Copy link
Contributor

DamianOsipiuk commented Aug 23, 2022

@TkDodo I would argue that devtools should actually bundle those.
From my perspective for UMD you should only include
https://unpkg.com/@tanstack/react-query@4.3.0-beta.3/build/umd/index.production.js
and
https://unpkg.com/@tanstack/react-query-devtools@4.3.0-beta.3/build/umd/index.production.js

Without the need of importing additional intermediate dependencies.
This is also the case for react-query which contains query-core bundled, so users do not have to think about importing it.

What do you think?


The other issue is that esm and cjs builds should not contain them - this needs to be fixed 😉

@TkDodo
Copy link
Collaborator Author

TkDodo commented Aug 23, 2022

@DamianOsipiuk I generally agree with that, however, the production devtools should effectively be "empty". The Devtools and DevtoolsPanel is just a function that returns null - no dependency is needed.
Especially match-sorter is easily visible, and I've also done a production build of a testing repo, where I can see that match-sorter is also included, even though it is not used :)

The other issue is that esm and cjs builds should not contain them - this needs to be fixed 😉

Ha, okay :)

@DamianOsipiuk
Copy link
Contributor

Oh, right. They need to be bundled in dev only. 👍

@TkDodo
Copy link
Collaborator Author

TkDodo commented Aug 23, 2022

any idea what to do about the production devtools lazy import?

@DamianOsipiuk
Copy link
Contributor

Not yet, but i will look into it.

@TkDodo
Copy link
Collaborator Author

TkDodo commented Aug 24, 2022

testing with 4.3.0-beta.4:

  • umd builds are properly treeshaked (no devtools in production), dev-build contains all dependencies
  • ✅ create-react-app v4 shows the devtools in dev mode
  • ✅ create-react-app v4 removes devtools in prod build (this is the same as we had in RQ v3):
var v=function(){return null},y=function(){return null};t.ReactQueryDevtools=v,t.ReactQueryDevtoolsPanel=y
  • ✅ create-react-app v5 removes devtools in prod build even better - I find no traces of them at all.
  • 🟡 I was able to import the devtools in production via:
const ReactQueryDevtoolsProduction = React.lazy(() =>
    import('@tanstack/react-query-devtools/build/lib/index.prod.js').then(d => ({
        default: d.ReactQueryDevtools,
    }))
)

however, that import path is not great. Could we somehow alias that to '@tanstack/react-query-devtools/production' ?

  • ❌ rendering the production devtools doesn't actually work in a production build. Here is the code:
function App() {
    const [showDevtools, setShowDevtools] = React.useState(false)

    React.useEffect(() => {
        // @ts-ignore
        window.toggleDevtools = () => setShowDevtools(old => !old)
    }, [])

    return (
        <QueryClientProvider client={queryClient}>
            <Example />
            { showDevtools && (
                <React.Suspense fallback={null}>
                    <ReactQueryDevtoolsProduction initialIsOpen />
                </React.Suspense>
            )}
        </QueryClientProvider>
    );
}

I can see the separate bundle being created, and it also gets loaded in the browser network tab when I do toggleDevtools(), however, it renders nothing. If I start the app in dev mode, it works. This is really weird because the bundle seems correct just from looking at it 🤔 .

looked into this for a bit now, it seems to be something with our useIsMounted hook:

export function useIsMounted() {
const mountedRef = React.useRef(false)
const isMounted = React.useCallback(() => mountedRef.current, [])
React[isServer ? 'useEffect' : 'useLayoutEffect'](() => {
mountedRef.current = true
return () => {
mountedRef.current = false
}
}, [])
return isMounted
}

the ref is never set to true, therefore, we render nothing. Don't know why yet...

  • ✅ the side-effect call to notifyManager.setBatchNotifyFunction is included in the production build

@DamianOsipiuk
Copy link
Contributor

however, that import path is not great. Could we somehow alias that to '@tanstack/react-query-devtools/production' ?

I can reintroduce that export, but it will only work with bundlers that fully supports exports, like vite.
react-scripts would have to import the ugly one
Unfortunately the issue with @tanstack/react-query-devtools/production is typescript bug that i have mentioned previously. So typescript will yell at you that it does not have type declarations, even though vite will compile successfully.

rendering the production devtools doesn't actually work in a production build. Here is the code:

I'm not sure about this particular piece of code but it worked for me with the following with react-scripts 4:

import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
// import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
import React from "react";
import { Example } from "./Example";

const queryClient = new QueryClient();

const ReactQueryDevtools = React.lazy(async () => {
  const devtools = await import(
    "@tanstack/react-query-devtools/build/lib/index.prod.js"
  );

  return {
    default: devtools.ReactQueryDevtools,
  };
});

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <Example />
      <ReactQueryDevtools initialIsOpen />
    </QueryClientProvider>
  );
}

export default App;

@TkDodo
Copy link
Collaborator Author

TkDodo commented Aug 25, 2022

I can reintroduce that export, but it will only work with bundlers that fully supports exports, like vite.
react-scripts would have to import the ugly one

if that's fine with you, i think its okay.

I'm not sure about this particular piece of code but it worked for me with the following with react-scripts 4:

you are right! it works fine with react-scripts 4, but not with react-scripts 5. I up/downgraded back and forth for testing, and when I wrote the above summary, I missed that.

@DamianOsipiuk
Copy link
Contributor

DamianOsipiuk commented Aug 27, 2022

@TkDodo
additional import - #4090
not sure what could be the problem but you core works for me both for react scripts 4 and 5

Edit. It does not work with React.lazy


So it seems, when you change

React[isServer ? 'useEffect' : 'useLayoutEffect'](() => { 

to

React['useEffect'](() => { 

or

React['useLayoutEffect'](() => { 

It starts working again...

@TkDodo
Copy link
Collaborator Author

TkDodo commented Aug 28, 2022

@DamianOsipiuk that's an interesting find! we need the isServer check because useLayoutEffect doesn't work on the server. However, I think we could simply always useEffect here? Or maybe it also works if we change isServer to be a function, because then the result cannot be optimized away:

- export const isServer = typeof window === 'undefined'
+ export const isServer = () => typeof window === 'undefined'

- React[isServer ? 'useEffect' : 'useLayoutEffect'](() => { 
+ React[isServer() ? 'useEffect' : 'useLayoutEffect'](() => {

?

@TkDodo
Copy link
Collaborator Author

TkDodo commented Aug 28, 2022

@DamianOsipiuk I've switched to only using useEffect and removed the isServer check completely:

I'll quickly re-test this with the latest beta. This was the last issue, right? If that works, we would be ready to merge?

@TkDodo
Copy link
Collaborator Author

TkDodo commented Aug 28, 2022

@DamianOsipiuk toggling devtools now works in react-scripts v5. The typescript import issue is still there, but I think for now, I'll just add documentation that you can import with the long path.

@DamianOsipiuk
Copy link
Contributor

@TkDodo Typescript issue will go away if you change the moduleResolution to NodeNext. We could potentially add that to docs.

And yes, i think that was the last issue.

@TkDodo
Copy link
Collaborator Author

TkDodo commented Aug 28, 2022

I added this paragraph, is that about right?

5e145fc

@DamianOsipiuk
Copy link
Contributor

Yup, although i think that TS 4.7 is required.

@TkDodo
Copy link
Collaborator Author

TkDodo commented Aug 28, 2022

I got 4.5 from their docs:

@DamianOsipiuk
Copy link
Contributor

@TkDodo
Copy link
Collaborator Author

TkDodo commented Aug 28, 2022

okay, I updated it: 40c3491

@igortas
Copy link

igortas commented Jun 6, 2023

@TkDodo
Version 5.0.0-beta-alpha.56 complains for lazy loding dev tools for production, same goes for lower version, at least I've tried 35 and it's the same... Tried adding index.d.ts file with declare module '@tanstack/react-query-devtools/build/lib/index.prod.js', not helping too...

Module not found: Error: Package path ./build/lib/index.prod.js is not exported from package /home/igor/projects/ToolbarApp/node_modules/@tanstack/react-query-devtools (see exports field in /home/igor/projects/ToolbarApp/node_modules/@tanstack/react-query-devtools/package.json)

@TkDodo
Copy link
Collaborator Author

TkDodo commented Jun 6, 2023

That's more something for @ardeora

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request esm
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants