gatsbyjs / gatsby

The best React-based framework with performance, scalability and security built in.
https://www.gatsbyjs.com
MIT License
55.27k stars 10.31k forks source link

Infinite loop with graphqlTypegen and tailwindcss #35775

Closed nrandell closed 2 years ago

nrandell commented 2 years ago

Preliminary Checks

Description

If you have a project with tailwindcss and graphqlTypegen the build triggers an infinite loop due to the gatsby-types.d.ts changing.

Reproduction Link

https://github.com/nrandell/gatsby-tailwind-loop

Steps to Reproduce

yarn install yarn develop --verbose

Expected Result

A single pass at building

...

You can now view my-gatsby-site in the browser.
⠀
  http://localhost:8000/
⠀
View GraphiQL, an in-browser IDE, to explore your site's data and schema
⠀
  http://localhost:8000/___graphql
⠀
Note that the development build is not optimized.
To create a production build, use gatsby build
⠀
success Building development bundle - 11.094s
verbose Transition to "initialGraphQLTypegen"
verbose Successfully created schema.graphql
success Writing page-data.json files to public directory - 0.099s - 3/4 40.41/s
verbose Wrote fragments.graphql file to .cache
success Generating GraphQL and TypeScript types - 0.251s
verbose Transition to "waiting"

Actual Result

It continues a number of times - some projects are infinite!

You can now view my-gatsby-site in the browser.
⠀
  http://localhost:8000/
⠀
View GraphiQL, an in-browser IDE, to explore your site's data and schema
⠀
  http://localhost:8000/___graphql
⠀
Note that the development build is not optimized.
To create a production build, use gatsby build
⠀
success Building development bundle - 11.263s
verbose Transition to "initialGraphQLTypegen"
verbose Successfully created schema.graphql
success Writing page-data.json files to public directory - 0.090s - 3/4 44.59/s
verbose Wrote fragments.graphql file to .cache
verbose Webpack file changed: D:\temp\ts\my-gatsby-site\src\gatsby-types.d.ts
success Generating GraphQL and TypeScript types - 0.321s
verbose Transition to "waiting"
verbose Transition to "runningQueries"
success onPreExtractQueries - 0.003s
verbose Re-Generating fragments.graphql & TS Types
success extract queries from components - 0.044s
verbose Transition to "runningQueries" > "waitingPendingQueries"
verbose Wrote fragments.graphql file to .cache
verbose Transition to "runningQueries" > "writingRequires"
success write out requires - 0.004s
verbose Transition to "runningQueries" > "calculatingDirtyQueries"
verbose Transition to "runningQueries" > "runningStaticQueries"
verbose Transition to "runningQueries" > "runningPageQueries"
verbose Transition to "runningQueries" > "waitingForJobs"
verbose Transition to "runningQueries" > "done"
verbose Transition to "recompiling"
⠋ Re-building development bundle
warn Warning: Event "xstate.after(200)#waitingMachine.aggregatingFileChanges" was sent to stopped service "waitingMachine". This service has already
reached its final state, and will not transition.
Event: {"type":"xstate.after(200)#waitingMachine.aggregatingFileChanges"}
success Re-building development bundle - 0.254s
verbose Webpack file changed: D:\temp\ts\my-gatsby-site\src
verbose Transition to "waiting"
success Writing page-data.json files to public directory - 0.027s - 0/1 37.55/s
verbose Transition to "runningQueries"
success onPreExtractQueries - 0.003s
verbose Re-Generating fragments.graphql & TS Types
success extract queries from components - 0.035s
verbose Transition to "runningQueries" > "waitingPendingQueries"
verbose Wrote fragments.graphql file to .cache
verbose Transition to "runningQueries" > "writingRequires"
success write out requires - 0.003s
verbose Transition to "runningQueries" > "calculatingDirtyQueries"
verbose Transition to "runningQueries" > "runningStaticQueries"
verbose Transition to "runningQueries" > "runningPageQueries"
verbose Transition to "runningQueries" > "waitingForJobs"
verbose Transition to "runningQueries" > "done"
verbose Transition to "recompiling"
warn Warning: Event "xstate.after(200)#waitingMachine.aggregatingFileChanges" was sent to stopped service "waitingMachine". This service has already
reached its final state, and will not transition.
Event: {"type":"xstate.after(200)#waitingMachine.aggregatingFileChanges"}
success Re-building development bundle - 0.179s
verbose Webpack file changed: D:\temp\ts\my-gatsby-site\src
verbose Transition to "waiting"
success Writing page-data.json files to public directory - 0.029s - 0/1 34.74/s
verbose Transition to "runningQueries"
success onPreExtractQueries - 0.003s
verbose Re-Generating fragments.graphql & TS Types
success extract queries from components - 0.038s
verbose Transition to "runningQueries" > "waitingPendingQueries"
verbose Wrote fragments.graphql file to .cache
verbose Transition to "runningQueries" > "writingRequires"
success write out requires - 0.003s
verbose Transition to "runningQueries" > "calculatingDirtyQueries"
verbose Transition to "runningQueries" > "runningStaticQueries"
verbose Transition to "runningQueries" > "runningPageQueries"
verbose Transition to "runningQueries" > "waitingForJobs"
verbose Transition to "runningQueries" > "done"
verbose Transition to "recompiling"

Environment

System:
    OS: Windows 10 10.0.22000
    CPU: (16) x64 AMD Ryzen 7 PRO 4750G with Radeon Graphics
  Binaries:
    Node: 16.11.1 - C:\Program Files\nodejs\node.EXE
    Yarn: 1.22.18 - ~\AppData\Roaming\npm\yarn.CMD
    npm: 8.0.0 - C:\Program Files\nodejs\npm.CMD
  Languages:
    Python: 3.10.4
  Browsers:
    Edge: Spartan (44.22000.120.0), Chromium (101.0.1210.53), ChromiumDev (User home = 'C:\Users\nickr\AppData\Local\IISExpress'
IIS USER HOME configured)
  npmPackages:
    gatsby: ^4.15.0 => 4.15.1 
    gatsby-plugin-image: ^2.15.0 => 2.15.0 
    gatsby-plugin-manifest: ^4.15.0 => 4.15.0 
    gatsby-plugin-postcss: ^5.15.0 => 5.15.0 
    gatsby-plugin-react-helmet: ^5.15.0 => 5.15.0 
    gatsby-plugin-sharp: ^4.15.0 => 4.15.0 
    gatsby-plugin-sitemap: ^5.15.0 => 5.15.0 
    gatsby-source-filesystem: ^4.15.0 => 4.15.0 
    gatsby-transformer-sharp: ^4.15.0 => 4.15.0

Config Flags

No response

LekoArts commented 2 years ago

Hi!

This issue is happening due to a misconfiguration of Tailwind CSS on your end. They have this documentation section: https://tailwindcss.com/docs/content-configuration#styles-rebuild-in-an-infinite-loop

Exactly that is happening with your tailwind.config.js:

image

Once you don't watch the generated file anymore it doesn't rebuild.


So https://www.gatsbyjs.com/docs/how-to/styling/tailwind-css/#4-configuring-your-content-path should get a paragraph saying that when GraphQL Typegen is used the generated file should be ignored.

nrandell commented 2 years ago

That's what I thought. The problem is a lot of projects have quite a few subdirectories below src and a few utility files under src.

That's why I tend to use the wildcard option.

I did try to ignore the gatsby-types.d.ts file but that didn't seem to fix anything. The only way I could work around it was to output the gatsby-types.d.ts to a different directory and then update tsconfig.json.

LekoArts commented 2 years ago

According to glob tester website this should work:

content: ["./src/**/!(*.d).{ts,tsx}"],

But it doesn't, in my testing. So for this you should open a bug report with Tailwind CSS.

nrandell commented 2 years ago

I've raised an issue on Tailwind CSS. Is it possible to provide a configuration option for the graphqlTypegen so we can specify the output file?

LekoArts commented 2 years ago

For that you'll want to open a feature request here: https://github.com/gatsbyjs/gatsby/discussions/categories/ideas-feature-requests

nrandell commented 2 years ago

For that you'll want to open a feature request here: https://github.com/gatsbyjs/gatsby/discussions/categories/ideas-feature-requests

Done at https://github.com/gatsbyjs/gatsby/discussions/35779

Thanks

nrandell commented 2 years ago

Another question on this - is there a reason why this file is re-created each time? Surely it should only be created if something has changed.

nrandell commented 2 years ago

Just had a response back from tailwind on the issue I raised.

Hey, thanks for the report!

The core of the problem here is that, since Gatsby is using webpack internally, only directories are watched and not globs. We still pass the glob along, it's just that it is ignored by postcss-loader and/or webpack. This is just an unfortunate webpack limitation. We do some filtering in Tailwind CSS when rebuilding to skip doing work when changed files do not match the glob. However, we do not have the ability to prevent webpack from running at all.

Instead, I would suggest updating your content array glob to be a bit more strict so it doesn't cover the entire src folder. The following glob is rooted at ./src/pages instead of ./src and will prevent the rebuild loop from happening:

content: ["./src/pages/*.tsx"], An alternative is using the Tailwind CLI alongside Gatsby using something like concurrently to run the development server and the Tailwind CLI. We support all the fancy globs there as we're able to control file watching directly in it rather than rely on the tool Tailwind CSS is being integrated with. We don't have a guide for using Gastby and the Tailwind CLI directly but you could possibly adapt the instructions from our Remix guide which does do this. You'll specifically want to look at the package.json scripts there.

So it looks like they don't have a solution to this that fits nicely. I suspect this issue will become more apparent once more people start using the graphql typegen functionality.

My workaround where I modify ts-codegen.js in the node_modules folder to change the name of the output file is working well on a couple of my projects for local testing, but will prevent me from migrating more projects to use the typegen functionality.

LekoArts commented 2 years ago

I can't promise a timeline for when options for graphqlTypegen are added, so you'll need to update your tailwind configuration.

The action item for this issue here will be updating our documentation to mention that you should update your content option like the Tailwind CSS folks said.

screendriver commented 2 years ago

Same issue here. Unfortunately "./src/pages/*.{ts,tsx}" does not work for me. I still have an infinite loop with that.

nrandell commented 2 years ago

If anyone has a similar issue, I've created a temporary plugin @bond-london/gatsby-graphql-typegen

It is pretty much a copy of the built in version, but allows you to pass an option in to configure the output file. You can see how I use it in the example https://github.com/nrandell/gatsby-tailwind-loop/blob/23f2a711929556822c1599e419940a4173970c4d/gatsby-config.ts#L35

You need to make sure that your tsconfig.json references gatsby-*.ts as in https://github.com/nrandell/gatsby-tailwind-loop/blob/23f2a711929556822c1599e419940a4173970c4d/tsconfig.json#L104 and it will work.

I'm going to start using it in some of our projects so I may make some changes, but in my small tests it's working so far.

sensedrive commented 2 years ago

Even content: ['./src/**/*.tsx'], is not working for, although it should only parse tsx files, which the definition file definitle not is.

LekoArts commented 2 years ago

Please report that to Tailwind, it's nothing we can do about :)

Ilham-Pratama commented 2 years ago

This is the solution for my case

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './src/pages/*.{js,jsx,ts,tsx}',
    './src/components/**/*.{js,jsx,ts,tsx}'
  ],
  theme: {},
  variants: {},
  plugins: []
};
therealgilles commented 2 years ago

The problem is that the gatsby-types.d.ts file is generated in the src directory. If there was an option to generate it somewhere else, the infinite loop would not happen. Generating a file in the same directory as source files is a bad idea anyway.

zhaohuanyuu commented 2 years ago

I can't promise a timeline for when options for graphqlTypegen are added, so you'll need to update your tailwind configuration.

The action item for this issue here will be updating our documentation to mention that you should update your content option like the Tailwind CSS folks said.

it's not work, It seems that you can only wait for the configuration to specify the .d.ts output

therealgilles commented 2 years ago

The alternative is to use the gatsby-plugin-typegen plugin instead:

   // See https://www.gatsbyjs.com/plugins/gatsby-plugin-typegen/
    {
      resolve: `gatsby-plugin-typegen`,
      options: {
        outputPath: `typegen/gatsby-types.d.ts`,
        emitSchema: {
          'typegen/gatsby-introspection.json': true,
          'typegen/gatsby-schema.graphql': true,
        },
        emitPluginDocument: {
          'typegen/gatsby-plugin-documents.graphql': true,
        },
      },
    },

I don't know if it does the same thing but at least you can should where everything goes.

nsbruce commented 2 years ago

This error originated with gatsby-source-filesystem for me. In my gatsby-config.ts I had

    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `src`,
        path: `${__dirname}/src/`,
        ignore: [`images/galleries/**/*`, `files/**/*`], // ignore other source-filesystems
      },
    },

Commenting this out fixed the infinite looping for me.

zhaohuanyuu commented 2 years ago

This error originated with gatsby-source-filesystem for me. In my gatsby-config.ts I had

    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `src`,
        path: `${__dirname}/src/`,
        ignore: [`images/galleries/**/*`, `files/**/*`], // ignore other source-filesystems
      },
    },

Commenting this out fixed the infinite looping for me.

Setting the source filesystem retrieval scope does work,Thanks for the ideas