Webpack’ing your GraphQL Documents
Dhaivat Pandya
When building a GraphQL application, there are benefits that come from placing your GraphQL query documents in their own files rather than inline with your view components. For example, you can get simpler editor and tooling support since the tools can look at static files instead of trying to parse application code. Also, it prevents you from accidentally manipulating queries at runtime. However, until now it has been difficult to do with our GraphQL webpack loader since there was no way to have different queries share GraphQL fragments.
This is a short post that describes one of the features we recently built into our Webpack loader for GraphQL documents — graphql-tag — that solves this problem.
Until now, the loader only gave you the ability to load a query from a single file, but with a recent update you can now import fragment definitions from other .graphql
files. This makes it easy to place GraphQL documents outside of your view component definitions and share fragments across those documents. Now that the support for these files is fully featured, you can easily take advantage of built-in editor code highlighting for .graphql
files, for example on GitHub:
Using it
Right now, most Apollo Client apps are written by putting queries inside JavaScript template literals with a gql
tag:
export const COMMENT_QUERY = gql` query Comment($repoName: String!) { … } }`;const withData = graphql(COMMENT_QUERY, { // options });
This is a reasonable approach. But, if we don’t want to place our queries inline with our React components, we can do that with graphql-tag/loader.
To start using it, we edit the Webpack config so that it looks like this:
module.exports = { … module: { loaders: [{ test: /\.(graphql|gql)$/, exclude: /node_modules/, loader: ‘graphql-tag/loader’ }] }, … }
Now, we can place our query document in a file called CommentQuery.graphql,
and then import it within our Javascript code:
import COMMENT_QUERY from '../graphql/CommentQuery.graphql';
When the bundle is created, Webpack will load the .graphql
file and use the GraphQL parser in order to set COMMENT_QUERY
to a parsed version of the query contained within the .graphql
file. Now, let’s say that this query used a fragment spread internally:
query Comment($repoName: String!) { … ...CommentsPageComment … }fragment CommentsPageComment { … }
We could put both the query definition and the fragment definition in the same file. But, if the fragment is shared across multiple queries, we’d have to define it with every query that used. Instead, we can use graphql-tag/loader
’s preprocessor #import
statement. This is what our query file would look like:
#import "./CommentsPageComment.graphql"query Comment($repoName: String!) { … ...CommentsPageComment … }
and the file CommentsPageComment.graphql
would contain:
fragment CommentsPageComment on Comment { id postedBy { login html_url } createdAt content }
This allows us to import COMMENT_QUERY
as we did previously without worrying about having to import the fragment separately within our Javascript code.
That’s all you need to understand to start using graphql-tag/loader
in your projects. If you’d like to see an example, you can check out how we use .graphql
files and preprocessor #import
statements within our example app, GitHunt-React.
How it works
The implementation of graphql-tag/loader
is incredibly simple. Since it is a Webpack loader, it has to turn each .graphql
into a bit of Javascript code that Webpack can place into the bundle it creates. Let’s consider what happens when we try to import this file:
#import "./CommentsPageComment.graphql"query Comment($repoName: String!) { … ...CommentsPageComment … }
Notice that the first line is a GraphQL comment. This means that to an ordinary GraphQL parser, the import statement would be ignored entirely. But, graphql-tag/loader
will process it and replace it with a require
statement in the outputted code. It will then parse the whole document contained in this file and combine it with the definitions in the imported file. The Javascript code that graphql-tag/loader
outputs should look like this:
var doc = // JSON object that represents the parsed GraphQL document doc.definitions = doc.definitions .concat( require('CommentsPageComment.graphql').definitions ); module.exports = doc;
Notice that with the require
statement, graphql-tag/loader
will be executed again on CommentsPageComment.graphql
by Webpack. This makes it possible to have #import
statements within that file too. By generating this Javascript code, the loader makes it possible to import your .graphql
files from your Javascript code.
Next steps
Importing files that contain static queries makes it possible to build all kinds of neat tools, including support for persisted queries. We’ve actually built support for persisted queries on top of this improved Webpack loader, and we’ll have a blog post explaining how to use them soon!