graphql-code-generator-community icon indicating copy to clipboard operation
graphql-code-generator-community copied to clipboard

ReactRouterV7 with @graphql-codegen/typescript-react-apollo yields error: __vite_ssr_import_3__.useQuery is not a function

Open alicerocheman opened this issue 10 months ago • 1 comments

Which packages are impacted by your issue?

@graphql-codegen/typescript-react-apollo

Describe the bug

Issue

  1. In a ReactRouter V7 (as a framework) with vite and apollo:
  2. Once query hooks have been generated with @graphql-codegen/typescript-react-apollo
  3. the import of Apollo inside the generated file breaks the app with this error: TypeError: __vite_ssr_import_[importNb]__.useQuery is not a function

Your Example Website or App

https://stackblitz.com/edit/github-kocgurap-ascqncjf

Steps to Reproduce the Bug or Issue

  1. on the reproduction, run
npm install && npm run dev
  1. the app fails with error "vite_ssr_import_2.useQuery is not a function"

Expected behavior

The npx create-react-router@latest app should run.

Screenshots or Videos

Image

Platform

  • OS: macOS
  • NodeJS: tested on v18.20.3 && v20.16.0
  • graphql version: "graphql": "^16.10.0", "graphql-tag": "^2.12.6",
  • @graphql-codegen/* version(s): "@graphql-codegen/cli": "^5.0.4", "@graphql-codegen/near-operation-file-preset": "^3.0.0", "@graphql-codegen/typescript": "^4.1.3", "@graphql-codegen/typescript-operations": "^4.4.1", "@graphql-codegen/typescript-react-apollo": "^4.3.2",

Codegen Config File

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

const config: CodegenConfig = { schema: 'schema.graphql', documents: 'document.graphql', config: { gqlImport: 'graphql-tag#gql', }, generates: { 'types.ts': { plugins: [ 'typescript', 'typescript-operations', 'typescript-react-apollo', ], }, }, };

export default config;

Additional context

I thought the solution would be to import like this: import Apollo from '@apollo/client'; instead of the current: import * as Apollo from '@apollo/client'; but it doesn't seem to work either ('@apollo/client/index has no default export')

Failing test / Solution:

I've looked into this, but I don't know how to solve this

Unrelated issue:

I couldn't use the CodeSandbox link to create a reproduciton repo:

Image

alicerocheman avatar Feb 03 '25 15:02 alicerocheman

I have no idea how to fix this issue inside the lib, but I fixed it in my project by running the following script once I've generated my files:

/* eslint-disable no-console */
import * as fs from 'fs';
import * as path from 'path';

const generatedFilesDir = './app/gql';

fs.readdir(generatedFilesDir, (err, files) => {
  if (err) {
    console.error('Error reading directory:', err);
    return;
  }

  files.forEach((file) => {
    if (file.endsWith('.generated.ts')) {
      const filePath = path.join(generatedFilesDir, file);
      fs.readFile(filePath, 'utf8', (err, data) => {
        if (err) {
          console.error('Error reading file:', err);
          return;
        }

        // Remove the old import statement
        const dataWithoutOldImport = data.replace(
          /import \* as Apollo from '@apollo\/client';\s*/g,
          ''
        );

        // Find all Apollo.xxx and collect unique xxx
        const apolloRegex = /Apollo\.(\w+)/g;
        let match;
        const apolloMethods = new Set<string>();
        while ((match = apolloRegex.exec(dataWithoutOldImport)) !== null) {
          apolloMethods.add(match[1]);
        }

        // Create import statements for each unique xxx
        const importStatements = Array.from(apolloMethods)
          .map((method) => {
            if (/^[A-Z]/.test(method)) {
              return `import type { ${method} } from '@apollo/client/index.js';`;
            } else {
              return `import { ${method} } from '@apollo/client/index.js';`;
            }
          })
          .join('\n');

        // Replace Apollo.xxx with xxx
        const updatedData = dataWithoutOldImport.replace(apolloRegex, (match, p1) => p1);

        // Insert import statements at the top of the file
        const finalData = importStatements + '\n' + updatedData;

        fs.writeFile(filePath, finalData, 'utf8', (err) => {
          if (err) {
            console.error('Error writing file:', err);
          } else {
            console.log(`Updated file: ${filePath}`);
          }
        });
      });
    }
  });
});

alicerocheman avatar Feb 04 '25 08:02 alicerocheman