Graphql-tag: Babel plugin for graphql-tag

Created on 19 Dec 2016  Â·  22Comments  Â·  Source: apollographql/graphql-tag

I was thinking that a babel plugin could be a useful addition to graphql-tag. It would be of the same scope and capabilities of the webpack loader, simply parsing queries into an AST ahead of time, but allowing the queries to reside in the .js file. No ideas yet on how to handle referenced fragments, but the implementation should be simple for queries and mutations that don't require that capability.

Prior work

babel-plugin-graphql is similar in scope, but works differently. Can't share much code other than the boilerplate.
babel-relay-plugin is far more complex and actually validates the query against the schema. This capability is annulled by eslint-plugin-graphql

Implementation

I haven't written a babel plugin before, but after messing around in astexplorer.net for a little bit, it wouldn't be too hard. Plan would be to traverse the AST and look for tagged template literals that are identified with gql. Then the contents of the literal would be passed through graphql-tag's gql. The resulting object would then be recursively traversed converting it's properties to the corresponding babel node.

What are some thoughts on this idea and approach?

Most helpful comment

I'm using nextjs and can't use the webpack loader so I made a plugin here by modifying babel-plugin-inline-import. It doesn't support importing fragments yet but it was enough to get me started moving my queries into .graphql files.

Update: It now supports fragments

@stubailo @fubhy Let me know if there's anything I could do to make this more useful. Hopefully this doesn't completely overlap with the functionality of persistgraphql as I'm not really familiar with that.

All 22 comments

Do we think this is actually a good idea? Is there real data that shows it's better to compile the queries ahead of time for a medium-sized app with 10+ queries? It feels like the AST could get pretty large.

Anyway, I think it would be cool to add a Babel plugin in here, and I can't work on it personally but would be happy to help.

Presumably, this would have the same runtime impact as the webpack loader. Just with the queries being written inline instead of in an external file. The benefit I could see is for apps with no SSR. Having the queries pre-parsed could cut down on the time until the first query is sent. The downside being a bigger bundle, which could potentially increase the time to first query and paint.

I'll make a quick port of GitHunt-React using the loader and no SSR and see what impact that has on performance. Then mess around with both network and cpu throttling as well to see how different scenarios affect the performance. If most scenarios have the same or worse performance then this won't be worth doing.

The converted queries will be highly compressible code, and the 40KB minified graphql-tag and possibly parts of graphql (through dead code elimination) might even more than offset it…

@jtmthf @wmertens do you think this is better addressed by something like persisted queries where the client doesn't have to send the query at all (just an id?)

Even if you are only sending the ID, the client still needs to know the original query so persisted queries wouldn't significantly reduce the bundle size.

@stubailo i don't fully understand, why does the client need to know the original query? is that for caching purposes?

Yeah - basically the result doesn't include any information about aliases, fragments, or arguments, and we need that information to cache properly. For example:

query { a }

query { a: b }

Because of aliases, the two above queries will have identically shaped results and the only way to differentiate is to see what the field in the query was called.

I'm building an app with ssr and next.js . Next.js doesn't allow webpack loader due to the complexity of ssr. Having a babael plugin would help me use persisted queries.

Can't you run webpack before you run next?

On Thu, Feb 9, 2017 at 11:22 AM Khoa Nguyen notifications@github.com
wrote:

I'm building an app with ssr and next.js . Next.js doesn't allow webpack
loader due to the complexity of ssr. Having a babael plugin would help me
use persisted queries.

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/apollographql/graphql-tag/issues/31#issuecomment-278602269,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AADWlvuOFeE1HSvZQw_CQP_GXvRiwuvGks5raujogaJpZM4LQpR_
.

@wmertens Next.js will run the source code in Node environment so no webpack loader is allow.

From their docs:

Warning: Adding loaders to support new file types (css, less, svg, etc.) is not recommended because only the client code gets bundled via webpack and thus it won't work on the initial server rendering. Babel plugins are a good alternative because they're applied consistently between server/client rendering (e.g. babel-plugin-inline-react-svg).

@thangngoc89 btw you can also use persisted queries with the queries inside the app code, it's just not documented yet. Could you open an issue there to document it?

However it's definitely unfortunate that Next.js doesn't support this by bundling all of the code in the same way, that seems like it would be pretty important for a framework that has easy SSR as one of the main values.

Regardless of all these things having a babel plugin would be sweet. Someone should get started on it!

@stubailo oh sweet. Best news ever. I think you opened on PR for this already https://github.com/apollographql/persistgraphql/issues/7

I started working on this here jtmthf/babel-plugin-graphql-tag. It's not working just yet though. Do have support for external fragments which is nice.

Got it working! I'll add documentation and significantly more tests soon.

Edit:
It appears @boopathi attempted this project awhile back and currently holds the package name on NPM.

@jtmthf I'll as soon as I get back to the work computer. Any plans for importing a gql file directly?

@thangngoc89 it's possible, but it's pretty rare for a Babel plugin load an external file. To not complicate this plugin too much. Loading from an external file could be done from a separate plugin that scans for imports to (.gql|.graphql) files and then replaces the import statement with the template literal that could then be picked up by babel-plugin-graphql-tag

@thangngoc89 actually it works already, it's just not documented! That issue is when you're using something other than gql. Here are the options you need to pass into the CLI: https://github.com/apollographql/persistgraphql/blob/master/src/ExtractGQL.ts#L62-L66

So I guess it would be --inJsCode=true --extension='js' or similar. I haven't actually run it myself, only write unit tests 😄

I'm running into this issue when testing my React app with Mocha and the webpack loader recommended in the Apollo docs.

The loader works great for the app, allowing me to extract .graphql files from my code and simply import them.

However, when I want to run Enzyme tests on my components that use graphql() to inject the data from my server, the import of .graphql files doesn't work.

I tried to ignore the import (using the ignore-styles package, that allows you to specifiy extensions to ignore during future imports), but then graphql() complains that it wasn't passed a proper GraphQL DocumentNode, and I have no idea how I could mock / spy it up before rendering the component.

I believe that https://github.com/apollographql/persistgraphql has hit a wall due to https://github.com/apollographql/persistgraphql/issues/13. I think that the babel plugin you are proposing here could be the solution to this problem.

I'm using nextjs and can't use the webpack loader so I made a plugin here by modifying babel-plugin-inline-import. It doesn't support importing fragments yet but it was enough to get me started moving my queries into .graphql files.

Update: It now supports fragments

@stubailo @fubhy Let me know if there's anything I could do to make this more useful. Hopefully this doesn't completely overlap with the functionality of persistgraphql as I'm not really familiar with that.

I agree with @detrohutt, this also solves for users using Expo (since they dont expose their webpack, but rather their babelrc.

I also agree with moving this to the babel layer makes sense because I'd think in time, just like import blah.json should resolve, import blah.graphql could as well

i think a combination of https://www.npmjs.com/package/babel-plugin-inline-import-graphql-ast and https://github.com/gajus/babel-plugin-graphql-tag should resolve importing graphql fragments in next.js / react-native and pre-compiling queries to resolve the need for the graphql-tag runtime, respectively. thank you to @detrohutt and @gajus for your contributions!

Was this page helpful?
0 / 5 - 0 ratings