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

Allow fragments to be imported by name when using the webpack loader #257

Merged
merged 3 commits into from
Apr 29, 2021

Conversation

dobesv
Copy link
Contributor

@dobesv dobesv commented May 2, 2019

This makes fragments a bit more convenient to use.

Any packages that use graphql-tag/loader under the hood will also benefit.

Likely fix for #102 and #251

Note that if the fragment references other fragments (using fragment spread), you will get a document that has multiple fragments in it. In this case you will have to tell apollo which fragment you want using the fragmentName option.

@gabsprates
Copy link

Looks good.
I had a problem here when tried to use the readFragment() method using a fragment imported and processed by loader.
Any updates?

@emahuni
Copy link

emahuni commented Aug 9, 2019

why isn't this being merged?

@silesky
Copy link

silesky commented Sep 24, 2019

Can we merge this, please?

@dobesv
Copy link
Contributor Author

dobesv commented Sep 24, 2019

@gabsprates I wasn't sure how to interpret your comment - are you saying there is an issue with this PR or that this PR would have solved an issue you had?

@denkristoffer
Copy link

@jnwng: Friendly ping, is anything missing here? 🙂

@dulakm
Copy link

dulakm commented Dec 4, 2019

@jnwng: please, what's the status on this PR?

@valdoryu
Copy link

valdoryu commented Jan 6, 2020

@jnwng A new year, a new ping for this PR

@fsjsd
Copy link

fsjsd commented Jan 7, 2020

ping, need this

@jnwng
Copy link
Contributor

jnwng commented Jan 8, 2020

@dobesv if you’re able, please add a couple of tests verifying the behavior you’ve added here, as well as an addition to the docs to let people know how this works. thank you in advance!

@jnwng
Copy link
Contributor

jnwng commented Jan 8, 2020 via email

@dobesv dobesv force-pushed the fragment-named-exports branch 2 times, most recently from e70aa9c to a3c6fe9 Compare January 8, 2020 06:10
@dobesv
Copy link
Contributor Author

dobesv commented Jan 8, 2020

I added tests and updated the README. I can't quite tell why the tests are failing, the tests that fail don't seem related to my changes.

@dobesv
Copy link
Contributor Author

dobesv commented Jan 8, 2020

Tests are passing when I run them on my dev machine. Anyone else who if watching this thread who might know why tests are behaving differently on Travis? Maybe a node version issue?

@juliovedovatto
Copy link

I would love to use such feature. My project relies a lot on fragments and importing those fragments would save us time (also more organized).

Some points:

  • I cloned @dobesv repo and ran under node@13. All tests passed
  • I created a Docker, to test under node@10 and all tests passed
  • Also tested under Docker node@8 and all tests passed

I believe something went wrong with Travis CI @jnwng

My Docker setup:

Dockerfile

FROM node:10.8.0

RUN git clone https://github.com/dobesv/graphql-tag.git /app

WORKDIR /app

docker-compose.yml

version: "3.7"
services:
  graphql-tag:
    build:
      context: ./
    command: bash -c "cd /app && git checkout fragment-named-exports && git pull origin fragment-named-exports && rm -rf node_modules && yarn && yarn test"
    environment:
      NODE_ENV: development

Output:

graphql-tag_1  | Switched to a new branch 'fragment-named-exports'
graphql-tag_1  | Branch fragment-named-exports set up to track remote branch fragment-named-exports from origin.
graphql-tag_1  | From https://github.com/dobesv/graphql-tag
graphql-tag_1  |  * branch            fragment-named-exports -> FETCH_HEAD
graphql-tag_1  | Already up-to-date.
graphql-tag_1  | yarn install v1.9.2
graphql-tag_1  | [1/4] Resolving packages...
graphql-tag_1  | [2/4] Fetching packages...
graphql-tag_1  | (node:40) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.
graphql-tag_1  | [3/4] Linking dependencies...
graphql-tag_1  | [4/4] Building fresh packages...
graphql-tag_1  | $ npm run bundle
graphql-tag_1  |
graphql-tag_1  | > graphql-tag@2.10.1 bundle /app
graphql-tag_1  | > rollup -c && cp src/index.js.flow lib/graphql-tag.umd.js.flow
graphql-tag_1  |
graphql-tag_1  | Done in 7.34s.
graphql-tag_1  | yarn run v1.9.2
graphql-tag_1  | $ mocha test/graphql.js test/graphql-v0.12.js && tav --ci --compat
graphql-tag_1  |
graphql-tag_1  |
graphql-tag_1  |   gql 0
graphql-tag_1  |     ✓ parses queries
graphql-tag_1  |     ✓ parses queries when called as a function
graphql-tag_1  |     ✓ parses queries with weird substitutions
graphql-tag_1  |     ✓ allows interpolation of documents generated by the webpack loader
graphql-tag_1  |     ✓ parses queries through webpack loader
graphql-tag_1  |     ✓ parses single query through webpack loader
graphql-tag_1  |     ✓ parses single query and exports as default
graphql-tag_1  |     ✓ parses multiple queries through webpack loader
graphql-tag_1  |     ✓ parses fragments with variable definitions
graphql-tag_1  |     ✓ does not nest queries needlessly in named exports
graphql-tag_1  |     ✓ tracks fragment dependencies from multiple queries through webpack loader
graphql-tag_1  |     ✓ tracks fragment dependencies across nested fragments
graphql-tag_1  |     ✓ correctly imports other files through the webpack loader
graphql-tag_1  |     ✓ tracks fragment dependencies across fragments loaded via the webpack loader
graphql-tag_1  |     ✓ does not complain when presented with normal comments
graphql-tag_1  |     ✓ returns the same object for the same query
graphql-tag_1  |     ✓ returns the same object for the same query, even with whitespace differences
graphql-tag_1  |     ✓ returns the same object for the same fragment
graphql-tag_1  |     ✓ returns the same object for the same document with substitution
graphql-tag_1  |     ✓ can reference a fragment that references as fragment
graphql-tag_1  |     fragment warnings
graphql-tag_1  |       ✓ warns if you use the same fragment name for different fragments
graphql-tag_1  |       ✓ does not warn if you use the same fragment name for the same fragment
graphql-tag_1  |       ✓ does not warn if you use the same embedded fragment in two different queries
graphql-tag_1  |       ✓ does not warn if you use the same fragment name for embedded and non-embedded fragments
graphql-tag_1  |     unique fragments
graphql-tag_1  |       ✓ strips duplicate fragments from the document
graphql-tag_1  |       ✓ ignores duplicate fragments from second-level imports when using the webpack loader
graphql-tag_1  |
graphql-tag_1  |   gql 1
graphql-tag_1  |     ✓ parses queries
graphql-tag_1  |     ✓ parses queries when called as a function
graphql-tag_1  |     ✓ parses queries with weird substitutions
graphql-tag_1  |     ✓ allows interpolation of documents generated by the webpack loader
graphql-tag_1  |     ✓ parses queries through webpack loader
graphql-tag_1  |     ✓ parses single query through webpack loader
graphql-tag_1  |     ✓ parses single query and exports as default
graphql-tag_1  |     ✓ parses multiple queries through webpack loader
graphql-tag_1  |     ✓ parses fragments with variable definitions
graphql-tag_1  |     ✓ does not nest queries needlessly in named exports
graphql-tag_1  |     ✓ tracks fragment dependencies from multiple queries through webpack loader
graphql-tag_1  |     ✓ tracks fragment dependencies across nested fragments
graphql-tag_1  |     ✓ correctly imports other files through the webpack loader
graphql-tag_1  |     ✓ tracks fragment dependencies across fragments loaded via the webpack loader
graphql-tag_1  |     ✓ does not complain when presented with normal comments
graphql-tag_1  |     ✓ returns the same object for the same query
graphql-tag_1  |     ✓ returns the same object for the same query, even with whitespace differences
graphql-tag_1  |     ✓ returns the same object for the same fragment
graphql-tag_1  |     ✓ returns the same object for the same document with substitution
graphql-tag_1  |     ✓ can reference a fragment that references as fragment
graphql-tag_1  |     fragment warnings
graphql-tag_1  |       ✓ warns if you use the same fragment name for different fragments
graphql-tag_1  |       ✓ does not warn if you use the same fragment name for the same fragment
graphql-tag_1  |       ✓ does not warn if you use the same embedded fragment in two different queries
graphql-tag_1  |       ✓ does not warn if you use the same fragment name for embedded and non-embedded fragments
graphql-tag_1  |     unique fragments
graphql-tag_1  |       ✓ strips duplicate fragments from the document
graphql-tag_1  |       ✓ ignores duplicate fragments from second-level imports when using the webpack loader
graphql-tag_1  |
graphql-tag_1  |   gql 0
graphql-tag_1  |     ✓ is correct for a simple query
graphql-tag_1  |     ✓ is correct for a fragment
graphql-tag_1  |
graphql-tag_1  |   gql 1
graphql-tag_1  |     ✓ is correct for a simple query
graphql-tag_1  |     ✓ is correct for a fragment
graphql-tag_1  |
graphql-tag_1  |
graphql-tag_1  |   56 passing (97ms)
graphql-tag_1  |
graphql-tag_1  | Done in 1.83s.
graphql-tag_graphql-tag_1 exited with code 0

@abdavid
Copy link

abdavid commented Apr 23, 2020

Yet another friendly ping :)

@MGray55
Copy link

MGray55 commented Apr 29, 2020

Is this just pending due to merge conflicts?

@dobesv dobesv force-pushed the fragment-named-exports branch from a3c6fe9 to 8716145 Compare April 29, 2020 17:09
@dobesv
Copy link
Contributor Author

dobesv commented Apr 29, 2020

I rebased on master, pushed, and tested again. Looks like the tests are passing now, which is great.

@jnwng any chance you would consider merging this PR now?

@xjunior
Copy link

xjunior commented Jun 2, 2020

Any chance this is going in any soon? In my experience importing graphql queries and not being able to mix them with fragments makes the use of graphql-tag/loader very limited.

@dobesv
Copy link
Contributor Author

dobesv commented Jun 2, 2020

Note that as a workaround you can import a query document that uses the fragment you want to use, and use the fragmentName option to readFragment or writeFragment to indicate the fragment. This change does make the imports more explicit in the code, though.

@thiagopradi
Copy link

@jnwng - is there anything that I can do to help merge this PR? happy to help if needed.

@lucasconstantino
Copy link
Contributor

For those who don't wanna fork and still desire to use this: you can patch graphql-tag with patch-package. After you install this, create a file at ./patches/graphql-tag+2.11.0.patch with this content:

diff --git a/node_modules/graphql-tag/README.md b/node_modules/graphql-tag/README.md
index 56eb23b..f69a219 100644
--- a/node_modules/graphql-tag/README.md
+++ b/node_modules/graphql-tag/README.md
@@ -193,6 +193,32 @@ For **create-react-app** < v2, you'll either need to eject or use [react-app-rew
 
 Testing environments that don't support Webpack require additional configuration. For [Jest](https://facebook.github.io/jest/) use [jest-transform-graphql](https://github.com/remind101/jest-transform-graphql).
 
+#### Support for fragments
+
+With the webpack loader, you can import fragments by name:
+
+In a file called `query.gql`:
+```graphql
+fragment MyFragment1 on MyType1 {
+  ...
+}
+
+fragment MyFragment2 on MyType2 {
+  ...
+}
+```
+
+And in your JavaScript:
+
+```javascript
+import { MyFragment1, MyFragment2 } from 'query.gql'
+```
+
+Note: If your fragment references other fragments, the resulting document will
+have multiple fragments in it.  In this case you must still specify the fragment
+name when using the fragment.  For example, with `apollo-client` you would specify
+the `fragmentName` option when using the fragment for cache operations. 
+
 ### Warnings
 
 This package will emit a warning if you have multiple fragments of the same name. You can disable this with:
diff --git a/node_modules/graphql-tag/loader.js b/node_modules/graphql-tag/loader.js
index 4ceac4d..5f554e5 100644
--- a/node_modules/graphql-tag/loader.js
+++ b/node_modules/graphql-tag/loader.js
@@ -53,7 +53,7 @@ module.exports = function(source) {
   // at compile time, and then uses those at load time to create minimal query documents
   // We cannot do the latter at compile time due to how the #import code works.
   let operationCount = doc.definitions.reduce(function(accum, op) {
-    if (op.kind === "OperationDefinition") {
+    if (op.kind === "OperationDefinition" || op.kind === "FragmentDefinition") {
       return accum + 1;
     }
 
@@ -166,7 +166,7 @@ module.exports = function(source) {
     `
 
     for (const op of doc.definitions) {
-      if (op.kind === "OperationDefinition") {
+      if (op.kind === "OperationDefinition" || op.kind === "FragmentDefinition") {
         if (!op.name) {
           if (operationCount > 1) {
             throw "Query/mutation names are required for a document with multiple definitions";
diff --git a/node_modules/graphql-tag/test/graphql.js b/node_modules/graphql-tag/test/graphql.js
index e77af23..1c4c8f8 100644
--- a/node_modules/graphql-tag/test/graphql.js
+++ b/node_modules/graphql-tag/test/graphql.js
@@ -141,7 +141,18 @@ describe('gql', () => {
     assert.equal(Q3[1].name.value, 'F1');
     assert.equal(Q3[2].name.value, 'F2');
 
-  });
+      const F1 = module.exports.F1.definitions;
+      const F2 = module.exports.F2.definitions;
+      const F3 = module.exports.F3.definitions;
+
+      assert.equal(F1.length, 1);
+      assert.equal(F1[0].name.value, 'F1');
+      assert.equal(F2.length, 1);
+      assert.equal(F2[0].name.value, 'F2');
+      assert.equal(F3.length, 1);
+      assert.equal(F3[0].name.value, 'F3');
+
+    });
 
   it('tracks fragment dependencies across nested fragments', () => {
     const jsSource = loader.call({ cacheable() {} }, `
@@ -179,8 +190,22 @@ describe('gql', () => {
     assert.equal(Q1[2].name.value, 'F22');
     assert.equal(Q1[3].name.value, 'F11');
 
-    assert.equal(Q2.length, 1);
-  });
+      assert.equal(Q2.length, 1);
+
+      const F11 = module.exports.F11.definitions;
+      const F22 = module.exports.F22.definitions;
+      const F33 = module.exports.F33.definitions;
+
+      assert.equal(F11.length, 1);
+      assert.equal(F11[0].name.value, 'F11');
+      assert.equal(F22.length, 2);
+      assert.equal(F22[0].name.value, 'F22');
+      assert.equal(F22[1].name.value, 'F11');
+      assert.equal(F33.length, 3);
+      assert.equal(F33[0].name.value, 'F33');
+      assert.equal(F33[1].name.value, 'F22');
+      assert.equal(F33[2].name.value, 'F11');
+    });
 
   it('correctly imports other files through the webpack loader', () => {
     const query = `#import "./fragment_definition.graphql"

@webdeb
Copy link

webdeb commented Dec 27, 2020

#331 for ref

@dobesv
Copy link
Contributor Author

dobesv commented Dec 28, 2020

If you're using yarn 2 it has a built in package patching method you can use instead of patch-package

@@ -161,12 +161,12 @@ module.exports = function(source) {

return newDoc;
}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can imagine, that this line produces a mental dissonance on the apollo team. They don't know exactly why they can't merge this, they just know that they cannot merge it.

@dobesv removing this line will make wonders

@flzozaya
Copy link

Are there any plans to merge this, please?

@Vincz
Copy link

Vincz commented Apr 29, 2021

Hi guys. This feature is really needed with the new cache modification system (readFragment, writeFragment, ...).
And it's just two lines of code ...

ping @jnwng
ping @benjamn
ping @hwillson

@hwillson hwillson self-assigned this Apr 29, 2021
dobesv and others added 3 commits April 29, 2021 19:25
@hwillson hwillson force-pushed the fragment-named-exports branch from bfe2436 to 48cb13f Compare April 29, 2021 23:28
Copy link
Member

@hwillson hwillson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks very much @dobesv!

@hwillson hwillson changed the base branch from master to main April 29, 2021 23:31
@hwillson hwillson merged commit 81cc596 into apollographql:main Apr 29, 2021
@hwillson
Copy link
Member

Available in graphql-tag@2.12.4.

@Vincz
Copy link

Vincz commented Apr 30, 2021

Thank you @hwillson !

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

Successfully merging this pull request may close these issues.