tsdx: "Invalid hook call" error when importing a TSDX library with styled-components

Current Behavior

I’m building a private library with tsdx and would like to add styled-components there. When I do it, they work within the tsdx project but when I import those components in other projects (next.js/CRA using already styled-components inside), I get the following error:

Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
Screen Shot 2020-12-24 at 4 43 56 PM

Expected behavior

I would like to be able to use those styled-components exactly like any other react, or plain js function I’m able to use with tsdx, so they can be reused in my projects.

Especially when the test for those styled-components works and they get rendered correctly inside storybook.

Suggested solution(s)

Please, provide a concise way to enable tsdx-styled-components to use styled-components and export them correctly 🙏.

Additional context

I isolated this problem in a small project and prepared the steps to reproduce it:

  1. Create an empty project

    npx tsdx create tsdx-styled-components
    

    And uploaded to Github

  2. Add styled-components to it and a small component exported in the index

    With the second commit I added styled-components to the project, they get render correctly in storybook and test pass correctly for those styled-components components.

  3. Create a new next.js project and consume the library locally

    • Create a new project with yarn create next-app --example with-typescript next-ts-styled-components-tsdx-host.

    • Then yarn build the tsdx-styled-components.

    • yarn add ../tsdx-styled-components in next-ts-styled-components-tsdx-host (just to use it locally before registering)

    • Modify the pages/index.tsx file to use the new library:

      import Link from "next/link";
      import { Thing, SimpleStyledH1Application } from "tsdx-styled-components";
      import Layout from "../components/Layout";
      
      const IndexPage = () => (
        <Layout title="Home | Next.js + TypeScript Example">
          <Thing></Thing>
          {/* This causes the break, because is a styled-component */}
          <SimpleStyledH1Application />
          <h1>Hello Next.js 👋</h1>
          <p>
            <Link href="/about">
              <a>About</a>
            </Link>
          </p>
        </Layout>
      );
      
      export default IndexPage;
      

      I’m creating a new project just to verify, but we get the same error in our CRA, next.js projects with styled-components configured.

      SimpleStyledH1Application causes the error, if you comment it, the page renders correctly.

  4. Add the workaround described in https://github.com/formium/tsdx/issues/543 doesn’t work.

    With the third commit,add styled-components/macro version and adds babel-plugin-macros to .babelrc as described https://github.com/formium/tsdx/issues/543 & https://github.com/formium/tsdx/pull/644.

Your environment

 System:
    OS: macOS 11.1
    CPU: (16) x64 Intel(R) Core(TM) i9-9980HK CPU @ 2.40GHz
    Memory: 79.52 MB / 32.00 GB
    Shell: 5.8 - /bin/zsh
  Binaries:
    Node: 14.13.1 - /usr/local/bin/node
    Yarn: 1.22.10 - /usr/local/bin/yarn
    npm: 6.14.8 - /usr/local/bin/npm
  Browsers:
    Chrome: 87.0.4280.88
    Chrome Canary: 89.0.4366.0
    Firefox Developer Edition: 83.0
    Safari: 14.0.2

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Reactions: 9
  • Comments: 17

Most upvoted comments

We found a dirty hack to make it work in local finally. As I said, it will work perfectly when the project is running with the default configuration in the projects, but when we want to run the lib project locally and see the changes in the host is when we face the problems.

We realized the problem was with duplication react version, meaning the host project has 2 copies of react, the default one /next-ts-styled-components-tsdx-host/node-modules/react and /next-ts-styled-components-tsdx-host/node-modules/tsdx-styled-components/node-modules/react and just deleting the later we get the project working, the problem is if we do that, then we can’t successfully build the lib project (needs react).

So our solution finally is what the official React guide suggest:

This problem can also come up when you use npm link or an equivalent. In that case, your bundler might “see” two Reacts — one in application folder and one in your library folder. Assuming myapp and mylib are sibling folders, one possible fix is to run npm link …/myapp/node_modules/react from mylib. This should make the library use the application’s React copy.

In our case, having both projects in the same folder, in the tsdx-styled-components (lib project) we execute npm link ../next-ts-styled-components-tsdx-host/node_modules/react and makes everything work.

Not sure if there is a better way, but this works.

Hey @timosnel , I pretty sure you only need to execute the same solution I posted,

cd my-package-name;
npm link ../your-host/node_modules/react

I hope it works also for you,

We are having the same exact problem using Next.js. The link works fine if we use a webpack alias for CRA, but for Next.js there is no way to make it work. Did anyone find a solution/fix?

Good to know someone else is facing the same issue. I would really love to find a solution. I hope someone can put light on it, as otherwise, we can’t have libs packages using tsdx.

Same issue here… this really should be addressed, else it’s our only blocker to us using tsdx

Hi @robertovg

Are you using yarn link or npm link to link your app with your library?

A similar issue is discussed here: https://github.com/facebook/react/issues/13991

A possible solution with craco

Override create react app configuration if you use create react app scripts.

  • Craco

  • Install craco and craco-alias.

yarn add -D @craco/craco craco-alias
  • Update craco.config.js
const CracoAlias = require('craco-alias');

// Source: https://github.com/facebook/react/issues/15315#issuecomment-638504372
module.exports = {
  plugins: [
    {
      plugin: CracoAlias,
      options: {
        source: 'options',
        baseUrl: './',
        aliases: {
          // described at https://github.com/facebook/react/issues/13991
          react: './node_modules/react',
          'react-dom': './node_modules/react-dom',
          'styled-components': './node_modules/styled-components',
        },
      },
    },
  ],
};

Reference: https://github.com/facebook/react/issues/15315#issuecomment-638504372