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

@graphql-codegen/client-preset-swc-plugin adds imports before "use client" #9445

Open
Tracked by #9489
victorandree opened this issue May 20, 2023 · 2 comments
Open
Tracked by #9489

Comments

@victorandree
Copy link

victorandree commented May 20, 2023

Which packages are impacted by your issue?

@graphql-codegen/cli, @graphql-codegen/client-preset

Describe the bug

@graphql-codegen/client-preset-swc-plugin inserts imports at the top of modules where you define queries. This breaks modules that are defined as React client components using the "use client" directive, which must appear at the top of the file - because the inserted imports end up before the directive.

This means you cannot define GraphQL queries in the same module as a client component when using the Next.js app directory.

Please see the example repository for a reproduction.

Your Example Website or App

https://github.com/victorandree/graphql-code-generator-swc-app-dir

Steps to Reproduce the Bug or Issue

  1. Create a client component in a Next.js app using the "app routes", requiring the use of a "use client" directive at the top of the module.
  2. Define a GraphQL query in this module.
  3. Set up GraphQL code generator with the "client preset" and using the SWC plugin.
  4. Try to build the Next.js app

The build will fail with a message like the following:

$ npm run dev

[...]
- error ./app/QueryComponent.tsx
ReactServerComponentsError:

The "use client" directive must be placed before other expressions. Move it to the top of the file to resolve this issue.

   ,-[/graphql-code-generator-swc-app-dir/app/QueryComponent.tsx:1:1]
 1 | 'use client';
   : ^^^^^^^^^^^^^
 2 |
 3 | import { useQuery } from '@apollo/client';
 4 | import { graphql } from '../gql';
   `----

Import path:
  ./app/QueryComponent.tsx
  ./app/page.tsx

Expected behavior

Since "use client" is required to be at the top of the file by the React Server Components RFC, I expect the SWC plugin to insert its imports after this directive.

Expressed differently: I expect to be able to define GraphQL queries in client components.

Screenshots or Videos

No response

Platform

  • OS: macOS
  • NodeJS: 16.19.1
  • graphql version: 16.6.0
  • @graphql-codegen/cli: 3.3.1
  • @graphql-codegen/client-preset: 3.0.1
  • @graphql-codegen/client-preset-swc-plugin: 0.2.0

Codegen Config File

import { CodegenConfig } from '@graphql-codegen/cli';

const config: CodegenConfig = {
  schema: 'schema.graphql',
  documents: 'app/**/*.tsx',
  generates: {
    'gql/': {
      preset: 'client',
      plugins: [],
    },
  },
};

export default config;

Additional context

A workaround is to define queries in a separate file, and import them in the client component. This is a bit annoying.

I'm not super-experienced in reading Rust, but I'm pretty sure that the imports are inserted by the plugin by module.body.insert(0, [...]) in lib.rs:183. I'm not sure if there's a simple way to insert it "a bit later" if there's a "use client" directive there.

Note: The SWC plugin crashes with the latest version of Next (13.4.3).

@YassinEldeeb YassinEldeeb mentioned this issue Jun 6, 2023
8 tasks
@BowlingX
Copy link

BowlingX commented Aug 4, 2023

I tried it out with using 1 as index and it works - There might be edge cases though

@victorandree
Copy link
Author

@BowlingX By "1 as index", do you mean passing a 1 as the first argument to module.body.insert, instead of 0?

Yeah, that should probably insert the import statement after the first ModuleItem. However, the first ModuleItem may not be a "use client" directive, so it's probably better to only apply this logic conditionally.

The code should probably check module.body, to find the index where the import declaration should be inserted. It should be possible to identify "use client" directives, or other module items, that should be placed before an import, and then insert imports after that index.

victorandree added a commit to victorandree/graphql-code-generator that referenced this issue Aug 15, 2023
When adding a "use client" directive to a module, it must come before
any other expressions. Instead of always inserting import declarations
as the first item, the SWC plugin now checks if the first expression in
a module's body is a "use client" directive and inserts its imports
after it, if that's the case.

Closes: dotansimha#9445
victorandree added a commit to victorandree/graphql-code-generator that referenced this issue Aug 18, 2023
When adding a "use client" directive to a module, it must come before
any other expressions. Instead of always inserting import declarations
as the first item, the SWC plugin now checks if the first expression in
a module's body is a "use client" directive and inserts its imports
after it, if that's the case.

Closes: dotansimha#9445
victorandree added a commit to victorandree/graphql-code-generator that referenced this issue Sep 28, 2023
When adding a "use client" directive to a module, it must come before
any other expressions. Instead of always inserting import declarations
as the first item, the SWC plugin now checks if the first expression in
a module's body is a "use client" directive and inserts its imports
after it, if that's the case.

Closes: dotansimha#9445
victorandree added a commit to victorandree/graphql-code-generator that referenced this issue Nov 16, 2023
When adding a "use client" directive to a module, it must come before
any other expressions. Instead of always inserting import declarations
as the first item, the SWC plugin now checks if the first expression in
a module's body is a "use client" directive and inserts its imports
after it, if that's the case.

Closes: dotansimha#9445
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants