Apollo-tooling: Flow Modern ignores output path and writes generated files next to input queries

Created on 16 Dec 2017  路  10Comments  路  Source: apollographql/apollo-tooling

Specifically, for the input file foo/queries.graphql it _always_ writes files to foo/__generated__/*, regardless of what output path is given.

If your source code is laid out to separate directories "read-only inputs -> generated source code" (for example, for easy build rules, for isolated paths for CI builds, etc), this is a challenge. With the current code the only way to avoid that is:

  • Create a temporary directory.
  • Copy the query file there.
  • Run apollo-codegen
  • Move the files from the temporary directory to your actual destination.

It would be helpful if output path were respected and the target directory name were customizable.

馃悶 bug

Most helpful comment

Specifying output location has been available since the initial commit and seems like a fundamental option for a file generator.

I'm not sure what you mean by the --colocate-dir-name flag. The query file path is already specified; how would that behaviour be different than this?

apollo-codegen generate queries/*.graphql --output queries/__generated__ --schema schema.json --target flow-modern

Or if query documents are scattered across directories, simply running the codegen for each of them with the appropriate output parameter:

for q in **/*.graphql; do
  apollo-codegen generate "$q" --output "$(dirname "$q")/__generated__" --schema schema.json --target flow-modern
done

Lots of use cases are covered by the simplest option.

As it is, I'm not sure what the rationale is for the *-modern targets to split up the type definitions into multiple files as they currently do, versus a single type definition file for queries against a particular schema. Splitting them forces the type declarations for input, enum, and scalar types to be duplicated in each of the files for the various operations, creating ambiguity even though those definitions should never be different for different operations.

All 10 comments

Thank you for filing this ticket and I agree that this should be done.

We went from 1 generated file to multiple generated files for various reasons, and just haven't had a chance to think about output path.

Can you give me an example of what your directory layout looks like + where you'd ultimately want files to go? I just want to make sure the implementation satisfies your use cases and any other use cases folks might have.

Sure. Currently as an input we have:

  • backend-queries/<backend-name>.graphql

Some codegen scripts write to:

  • src/gen/<backend-name>/*

Along with some system-specific code generation.

I don't think this directory layout is ideal, but flexibility is nice to have. The nice thing about separating the input and output directories like the above is that it's fairly easy to set up directory watchers or globbed Makefile rules.

the challenge with having flexibility around directory layout is knowing how much flexibility to offer.

right now, *-modern targets co-locate the queries intentionally so they're easy to find, since the type definitions are right next to your queries. it seems like this isn't ideal for tooling? what would be better for the tooling you have in mind?

@erydo ah -- this was added for other targets, and we should be able to add it for *-modern.

the only weirdness that needs to be considered is that the default behavior could not be configured via this option. What if we had two different sets of output related flags?

For outputting into a single directory:

--output ./

This would output one file per operation/fragment into the same directory.

For co-location (the default behavior):

--colocate --colocate-dir-name "__generated__"

Specifying output location has been available since the initial commit and seems like a fundamental option for a file generator.

I'm not sure what you mean by the --colocate-dir-name flag. The query file path is already specified; how would that behaviour be different than this?

apollo-codegen generate queries/*.graphql --output queries/__generated__ --schema schema.json --target flow-modern

Or if query documents are scattered across directories, simply running the codegen for each of them with the appropriate output parameter:

for q in **/*.graphql; do
  apollo-codegen generate "$q" --output "$(dirname "$q")/__generated__" --schema schema.json --target flow-modern
done

Lots of use cases are covered by the simplest option.

As it is, I'm not sure what the rationale is for the *-modern targets to split up the type definitions into multiple files as they currently do, versus a single type definition file for queries against a particular schema. Splitting them forces the type declarations for input, enum, and scalar types to be duplicated in each of the files for the various operations, creating ambiguity even though those definitions should never be different for different operations.

This issue is also the case with typescript-modern.

This seems to be fixed now. I really thing the for loop thing isn't a great solution for co-located queries.

I actually assumed that colocating types in __generated__ folders is intended behaviour. At least I'm used to it with relay. From what I can see, this is now not possible anymore.

Is this really the way to go? I found it quite hard to always reference a root directory or file that contains all my type definitions.

I haven't yet considered that this might have some benefits over the previous approach and it took me quite a while to figure out that colocating queries was possible with -modern targets. I feel that enforcing the output is not the best choice to be honest. Why don't we keep output optional, but for sure consider it during generation process in case it is set?

I would appreciate any links or discussions that might have already featured this topic to better understand why colocating might be a bad practice.

Apollo CLI now supports three methods of emitting modern types, which cover this issue!

  • __generated__ style: outputting files that match the original sources layout (default mode)
  • --outputFlat: split types but place all the files into a single folder (output arg must be a folder)
  • --outputFlat: place all types into a single file (output arg must be a file)
Was this page helpful?
0 / 5 - 0 ratings