From 9a2100eba4a7bc41bc99dd3c20e48cfb7cda0b92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pete=20Nyk=C3=A4nen?= Date: Sat, 3 Feb 2018 17:51:55 +0200 Subject: [PATCH] Add loader for .graphql files (#3909) * Add graphql loader to webpack config Signed-off-by: petetnt * Update README.md Signed-off-by: petetnt * Update react-scripts README.md Signed-off-by: petetnt * Add graphql jest transform Signed-off-by: petetnt * Add integration tests, pin versions in package.json Signed-off-by: petetnt * Tests expect regexp matchers Signed-off-by: petetnt * Use strict equal test instead Signed-off-by: petetnt * Escaping is hard Signed-off-by: petetnt * Add comment for signifying a different file * Update docs * Fix jest config * Remove node_modules exclusion * Update README.md * Inline graphql jest transform Signed-off-by: petetnt * Update copyright header Signed-off-by: petetnt * Use .graphql extension only Signed-off-by: petetnt --- .../config/jest/graphqlTransform.js | 18 ++++++++++++ .../config/webpack.config.dev.js | 5 ++++ .../config/webpack.config.prod.js | 5 ++++ .../kitchensink/integration/webpack.test.js | 10 +++++++ .../fixtures/kitchensink/src/App.js | 5 ++++ .../src/features/webpack/GraphQLInclusion.js | 15 ++++++++++ .../features/webpack/GraphQLInclusion.test.js | 17 +++++++++++ .../features/webpack/assets/graphql.graphql | 5 ++++ packages/react-scripts/package.json | 2 ++ .../scripts/utils/createJestConfig.js | 3 +- packages/react-scripts/template/README.md | 29 +++++++++++++++++++ 11 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 packages/react-scripts/config/jest/graphqlTransform.js create mode 100644 packages/react-scripts/fixtures/kitchensink/src/features/webpack/GraphQLInclusion.js create mode 100644 packages/react-scripts/fixtures/kitchensink/src/features/webpack/GraphQLInclusion.test.js create mode 100644 packages/react-scripts/fixtures/kitchensink/src/features/webpack/assets/graphql.graphql diff --git a/packages/react-scripts/config/jest/graphqlTransform.js b/packages/react-scripts/config/jest/graphqlTransform.js new file mode 100644 index 00000000000..5b70f07d6f2 --- /dev/null +++ b/packages/react-scripts/config/jest/graphqlTransform.js @@ -0,0 +1,18 @@ +// @remove-on-eject-begin +/** + * Copyright (c) 2018-present, Facebook, Inc. + * Copyright (c) 2016 Remind + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +// @remove-on-eject-end +'use strict'; + +const loader = require('graphql-tag/loader'); + +module.exports = { + process(src) { + return loader.call({ cacheable() {} }, src); + }, +}; diff --git a/packages/react-scripts/config/webpack.config.dev.js b/packages/react-scripts/config/webpack.config.dev.js index bd5d218cc8d..398b8bf53b7 100644 --- a/packages/react-scripts/config/webpack.config.dev.js +++ b/packages/react-scripts/config/webpack.config.dev.js @@ -278,6 +278,11 @@ module.exports = { }, ], }, + // The GraphQL loader preprocesses GraphQL queries in .graphql files. + { + test: /\.(graphql)$/, + loader: 'graphql-tag/loader', + }, // "file" loader makes sure those assets get served by WebpackDevServer. // When you `import` an asset, you get its (virtual) filename. // In production, they would get copied to the `build` folder. diff --git a/packages/react-scripts/config/webpack.config.prod.js b/packages/react-scripts/config/webpack.config.prod.js index 6c9a879e851..7b73dd787cd 100644 --- a/packages/react-scripts/config/webpack.config.prod.js +++ b/packages/react-scripts/config/webpack.config.prod.js @@ -320,6 +320,11 @@ module.exports = { ), // Note: this won't work without `new ExtractTextPlugin()` in `plugins`. }, + // The GraphQL loader preprocesses GraphQL queries in .graphql files. + { + test: /\.(graphql)$/, + loader: 'graphql-tag/loader', + }, // "file" loader makes sure assets end up in the `build` folder. // When you `import` an asset, you get its filename. // This loader doesn't use a "test" so it will catch all modules diff --git a/packages/react-scripts/fixtures/kitchensink/integration/webpack.test.js b/packages/react-scripts/fixtures/kitchensink/integration/webpack.test.js index e479be4b81a..bba497c49f3 100644 --- a/packages/react-scripts/fixtures/kitchensink/integration/webpack.test.js +++ b/packages/react-scripts/fixtures/kitchensink/integration/webpack.test.js @@ -31,6 +31,16 @@ describe('Integration', () => { ); }); + it('graphql files inclusion', async () => { + const doc = await initDOM('graphql-inclusion'); + const children = doc.getElementById('graphql-inclusion').children; + + // .graphql + expect(children[0].textContent.replace(/\s/g, '')).to.equal( + '{"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","variableDefinitions":[],"directives":[],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"test"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"test"},"value":{"kind":"StringValue","value":"test","block":false}}],"directives":[],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"test"},"arguments":[],"directives":[]}]}}]}}],"loc":{"start":0,"end":40,"source":{"body":"{\\ntest(test:\\"test\\"){\\ntest\\n}\\n}\\n","name":"GraphQLrequest","locationOffset":{"line":1,"column":1}}}}' + ); + }); + it('image inclusion', async () => { const doc = await initDOM('image-inclusion'); diff --git a/packages/react-scripts/fixtures/kitchensink/src/App.js b/packages/react-scripts/fixtures/kitchensink/src/App.js index 750f8a90b98..c45ef2a38e8 100644 --- a/packages/react-scripts/fixtures/kitchensink/src/App.js +++ b/packages/react-scripts/fixtures/kitchensink/src/App.js @@ -111,6 +111,11 @@ class App extends Component { this.setFeature(f.default) ); break; + case 'graphql-inclusion': + import('./features/webpack/GraphQLInclusion').then(f => + this.setFeature(f.default) + ); + break; case 'image-inclusion': import('./features/webpack/ImageInclusion').then(f => this.setFeature(f.default) diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/webpack/GraphQLInclusion.js b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/GraphQLInclusion.js new file mode 100644 index 00000000000..728b7a2847d --- /dev/null +++ b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/GraphQLInclusion.js @@ -0,0 +1,15 @@ +/** + * Copyright (c) 2018-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import A from './assets/graphql.graphql'; + +export default () => ( +

+ {JSON.stringify(A)} +

+); diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/webpack/GraphQLInclusion.test.js b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/GraphQLInclusion.test.js new file mode 100644 index 00000000000..914ce241bdd --- /dev/null +++ b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/GraphQLInclusion.test.js @@ -0,0 +1,17 @@ +/** + * Copyright (c) 2018-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import ReactDOM from 'react-dom'; +import GraphQLInclusion from './GraphQLInclusion'; + +describe('graphql files inclusion', () => { + it('renders without crashing', () => { + const div = document.createElement('div'); + ReactDOM.render(, div); + }); +}); diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/webpack/assets/graphql.graphql b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/assets/graphql.graphql new file mode 100644 index 00000000000..6125e344f55 --- /dev/null +++ b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/assets/graphql.graphql @@ -0,0 +1,5 @@ +{ + test(test: "test") { + test + } +} diff --git a/packages/react-scripts/package.json b/packages/react-scripts/package.json index ad4d345546b..35b5453216e 100644 --- a/packages/react-scripts/package.json +++ b/packages/react-scripts/package.json @@ -47,6 +47,8 @@ "find-pkg": "1.0.0", "fs-extra": "5.0.0", "globby": "7.1.1", + "graphql": "0.12.3", + "graphql-tag": "2.6.1", "html-webpack-plugin": "2.30.1", "identity-obj-proxy": "3.0.0", "jest": "22.1.2", diff --git a/packages/react-scripts/scripts/utils/createJestConfig.js b/packages/react-scripts/scripts/utils/createJestConfig.js index ea92a4f21ec..593d17090a7 100644 --- a/packages/react-scripts/scripts/utils/createJestConfig.js +++ b/packages/react-scripts/scripts/utils/createJestConfig.js @@ -38,7 +38,8 @@ module.exports = (resolve, rootDir, srcRoots) => { transform: { '^.+\\.(js|jsx|mjs)$': resolve('config/jest/babelTransform.js'), '^.+\\.css$': resolve('config/jest/cssTransform.js'), - '^(?!.*\\.(js|jsx|mjs|css|json)$)': resolve( + '^.+\\.(graphql)$': resolve('config/jest/graphqlTransform.js'), + '^(?!.*\\.(js|jsx|mjs|css|json|graphql)$)': resolve( 'config/jest/fileTransform.js' ), }, diff --git a/packages/react-scripts/template/README.md b/packages/react-scripts/template/README.md index dc105aaaecf..0163a85ccc9 100644 --- a/packages/react-scripts/template/README.md +++ b/packages/react-scripts/template/README.md @@ -27,6 +27,7 @@ You can find the most recent version of this guide [here](https://github.com/fac - [Post-Processing CSS](#post-processing-css) - [Adding a CSS Preprocessor (Sass, Less etc.)](#adding-a-css-preprocessor-sass-less-etc) - [Adding Images, Fonts, and Files](#adding-images-fonts-and-files) +- [Adding GraphQL files](#adding-graphql-files) - [Using the `public` Folder](#using-the-public-folder) - [Changing the HTML](#changing-the-html) - [Adding Assets Outside of the Module System](#adding-assets-outside-of-the-module-system) @@ -729,6 +730,34 @@ Please be advised that this is also a custom feature of Webpack. **It is not required for React** but many people enjoy it (and React Native uses a similar mechanism for images).
An alternative way of handling static assets is described in the next section. +## Adding GraphQL files + +> Note: this feature is available with react-scripts@2.0.0 and higher. + +If you are using GraphQL, you can **`import` GraphQL files in a JavaScript module**. + +By importing GraphQL queries instead of using a [template tag](https://github.com/apollographql/graphql-tag), they are preprocessed at build time. This eliminates the need to process them on the client at run time. It also allows you to separate your GraphQL queries from your code. You can put a GraphQL query in a file with a `.graphql` extension. + +Here is an example: + +```js +// query.graphql +{ + githubStats(repository: "facebook/react") { + stars + } +} + +// foo.js + +import query from './query.graphql'; + +console.log(query); +// { +// "kind": "Document", +// ... +``` + ## Using the `public` Folder >Note: this feature is available with `react-scripts@0.5.0` and higher.