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

Webpack loader fragment auto-resolution #37

Open
armstrjare opened this issue Jan 20, 2017 · 1 comment
Open

Webpack loader fragment auto-resolution #37

armstrjare opened this issue Jan 20, 2017 · 1 comment

Comments

@armstrjare
Copy link

armstrjare commented Jan 20, 2017

Regarding #import "my-fragment.gql" (#33) vs auto-resolving/loading fragments from the project where necessary. Bringing this in from a discussion from Twitter/Gist.

Suggestion: Instead of manually #importing files to load fragments for a query/mutation, rather have the webpack loader automatically include them by auto-discovering them in the project.


@armstrjare says:

If the fragments are stored in different parts of file tree, it's a pain to have to manually import them and maintain imports if refactoring etc.

#import '../../contacts/contact.fragment.gql'

Considering:

  1. Code generation via apollo-codegen assumes all fragments and queries are uniquely named
  2. Adding custom preprocessers makes things apollo-specific
  3. This adds extra developer overhead to splitting fragments into multiple files

Why doesn't the loader operate in the following way:

// webpack settings
graphqlLoader {
  // Define any paths/globs where the loader should try and resolve fragments from if they are used without being defined inline in the query files.
  resolvePaths: ['app/**/*.gql']
}

Loader semantics:

  1. Import passes through the loader
  2. Loader reads the file, and parses the query.
  3. Walks the query to see if there need to be any fragment imports that aren't defined inline
  4. If there are any unresolved Fragments, walk the resolvePaths, loading & parsing docs, to build up map of all defined fragments across the app. (Can cache this so don't need to repeat it on subsequent requires)
  5. Insert the just the additional fragments needed for the query into the parsed document structure.
  6. Return the document structure.

To me this:

  1. Eliminates the need for #import preprocessor (IMO this adds redundant complexity to the syntax, and extra managing of import paths etc., and it's non-standard)
  2. Keeps each loaded query minimal - each required file will only be the exact data needed for the query.

Thoughts?


@stubailo responds:

Does this require somehow computing file paths from the fragment names? Or is there a way to do it without that?

As a side note though if explicit imports are a good idea for JavaScript code why not for GraphQL queries as well? Both (1) and (2) apply to JS code just as much, and historically people have always chosen explicit importing over global namespaces.


@armstrjare responds:

Does this require somehow computing file paths from the fragment names? Or is there a way to do it without that?

Not at all - the loader would need to load and parse all resolved graphql files in the project, to determine what "fragments" are available to be used in the application. Only the extension/matcher is relevant - the rest of the info is purely based on the GQL in the file.

As a side note though if explicit imports are a good idea for JavaScript code why not for GraphQL queries as well? Both (1) and (2) apply to JS code just as much, and historically people have always chosen explicit importing over global namespaces.

Well, afaik this is because of the semantics of JS modules being isolated in scope and adding them on top of the existing JS runtime. Are explicit imports for all tokens needed because of this, rather than "we're going to do it this way in order to have explicit imports"?

If there was some form of "method missing" on the global scope (a la Ruby) then I wonder if autoloading would implemented along the lines of, say, how Rails does it?

With GQL we also have the benefit of it not being a programming language, but a data structure/definition. So we're not really comparing apples with apples. I'm not sure the same expectations apply?

There are some downsides of doing implicit fragment resolution though, but I think they outweigh the benefits:

  1. Fragments would be required to be uniquely named - or have some semantics on overloading

Are people even naming different fragments with the same name? As above, all the code-generation tools I've seen assume that all fragments are uniquely named. Is a reasonable constraint? Noting there is no concept of a GraphQL module or scope in the spec (?), and in GraphQL itself all Types are expected to be uniquely named.

  1. Need to load all GQL files in order to determine which fragments are available to be used.
    I'm not sure this is really an issue as a) files are generally pretty small; b) parsing is pretty fast; c) it can be loaded once for the first require() and then cached for future requires
@stubailo
Copy link
Contributor

I'm still a bit confused because my understanding is that to resolve stuff, Webpack needs a file path to that module. Can you point me to some docs about how a loader can scan all files in a project that match a certain pattern?

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