evenchange4 / graphql.macro

Compile GraphQL AST at build-time with babel-plugin-macros.
MIT License
239 stars 21 forks source link

Loading GraphQL from External Modules with Yarn Workspaces #119

Closed tubbo closed 2 years ago

tubbo commented 3 years ago

I'm trying to load a GraphQL query from an external package. It's part of a mono-repo, where all of the queries and type definitions are located in a @my-app/data package, and the React app was generated using create-react-app in its own package, called @my-app/ui. I'm managing this repo with Yarn Workspaces, and each package is its own workspace. Therefore, there should only be one node_modules/ directory, at the top level of the repo.

Here's what I tried originally:

import React from 'react'
import { useQuery } from '@apollo/client'
import { loader } from 'graphql.macro'

const HelloWorld = loader('@my-app/data/queries/hello-world.gql')

export default function App() {
  const { data, loading, error } = useQuery(HelloWorld)

  if (loading) {
    return <p>Loading...</p>
  }

  if (error) {
    return <p>Error: {error.message}</p>
  }

  return <p>Data: {data?.hello}</p>
}

When I did that, I got the following error:

[ui] Failed to compile.
[ui]
[ui] ./src/home.js
[ui] Error: /Users/tscott/Code/my-app/ui/src/home.js: graphql.macro: ENOENT: no such file or directory, open '/Users/tscott/Code/my-app/ui/node_modules/@my-app/data/queries/hello-world.gql

It seems like the macro is trying to look in a local node_modules/ dir, but not paying attention to where the directory actually is.

The workaround I'm using for now is:

const HelloWorld = loader('../../data/queries/hello-world.gql')
zaneclaes commented 3 years ago

I'm attempting to do the same thing. Did you ever find a solution? Also, have you tried loading a query from a library (rather than the main app)? If @my-app/ui tries to load a query, I end up with this issue.

tubbo commented 3 years ago

@zaneclaes I didn't, and since the React app itself uses TypeScript I dropped the use of this Babel macro since that wasn't going to work in the TypeScript compiler anyway. But if you do use TypeScript, I recommend trying out GraphQL Code Generator. Using the Apollo hooks plugin, I can just import a full on hook function instead of worrying about configuring Webpack to accept a .gql file:

import React from 'react'
import { useHelloWorldQuery } from '@my-app/graph/ql'

export default function App() {
  const { data, loading, error } = useHelloWorldQuery()

  if (loading) {
    return <p>Loading...</p>
  }

  if (error) {
    return <p>Error: {error.message}</p>
  }

  return <p>Data: {data?.hello}</p>
}

The @my-app/graph/ql module contains type definitions for the entire schema (including operations) in TypeScript, as well as typed Apollo hook functions that can be imported into whatever client needs them.

zaneclaes commented 3 years ago

Amazing; I use Typescript and the GraphQL code generator was exactly what I was looking for. I knew GQL schema and TS types felt redundant; this is a great solution. Thanks!