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

Using create react app with Graphql #1328

Closed
anhdn opened this issue Dec 29, 2016 · 14 comments
Closed

Using create react app with Graphql #1328

anhdn opened this issue Dec 29, 2016 · 14 comments

Comments

@anhdn
Copy link

anhdn commented Dec 29, 2016

Hello,

I'll start new project with new react app, new api. And I love using create-react-app and Graphql. So how can i start with both create-react-app and graphql on my project?

Thanks!

@EnoahNetzach
Copy link
Contributor

It should be as simple as installing Create React App, then running npm install graphql and using it in your project.

If with "start graphql" you mean how to start its server, you just have to follow its instructions, as CRA only handles the boilerplate with webpack, babel etc for serving/building/testing the frontend part.

😉

@anhdn
Copy link
Author

anhdn commented Dec 30, 2016

Hi EnoahNetzach,

How to connect CRA to Graphql? I think we need to use middleware to connect like apollo client.

@EnoahNetzach
Copy link
Contributor

EnoahNetzach commented Dec 30, 2016

What do you mean by "connecting"?

As long as GraphQL doesn't require you to add a webpack plugin (I might remember it wrong, but it doesn't), you should be able to just follow the instructions it provides.

If what you mean is a way to run the GraphQL server, again, you have to follow the instructions on how to run graphql-server (or any other server).

Create React App doesn't prevent you from adding other servers apart from the one it provides.

@tobkle
Copy link

tobkle commented Jan 21, 2017

Up to now, we are not able to load plain graphql files with the .graphql extension as such, as explained here, as this requires a 'graphql-tag/loader' entry in the webpack configuration:

There might be a work around by placing those files into .js files and defining the graphql tags inline as you would do it with gql`query something`, but so the editors (or at least my sublime) doesn't recognize the graphql syntax highlighting within the grapqhl tag string.

It'll be nice feature, if a create_react_app can load .graphql files by default.

I've tried to do it like follows, ....

cd node_modules/react_scripts
npm install --save graphql-tag  
vi config/webpack.config.dev.js

Find the default url loader exclusions...

      {
        exclude: [
          /\.html$/,
          /\.(js|jsx)$/,
          /\.css$/,
          /\.json$/,
          /\.svg$/
        ],

Add graphql and gql as exclusion to the default url loader ...

        exclude: [
          /\.html$/,
          /\.(js|jsx)$/,
          /\.css$/,
          /\.json$/,
          /\.svg$/,
          /\.graphql$/,
          /\.gql$/,
        ],

Now adding the graphql-tag/loader for .graphql and .gql files:
find // "file" loader for svg
change to...

      // "file" loader for svg
      {
        test: /\.svg$/,
        loader: 'file',
        query: {
          name: 'static/media/[name].[hash:8].[ext]'
        }
      },
      {
        test: /\.(graphql|gql)$/,
        exclude: /node_modules/,
        loader: 'graphql-tag/loader'
      }

...but the graphql-tag/loader doesn't resolve and lead to an Error in my App:

Module not found "graphql-tag/loader"

Has anyone an idea how to resolve this?

@tobkle
Copy link

tobkle commented Jan 21, 2017

Ok, resolved..

if I do this instead

yarn eject
yarn add graphql-tag
vi config/webpack.config.dev.js
vi config/webpack.config.prod.js

in the config files default loader I've added the following exclusions:

        exclude: [
          /\.html$/,
          /\.(js|jsx)$/,
          /\.css$/,
          /\.json$/,
          /\.svg$/,
          /\.graphql$/,
          /\.gql$/
        ],

..in the loader if added the graphql-tag/loader:

      {
          test: /\.(graphql|gql)$/,
          include: paths.appSrc,
          exclude: /node_modules/,
          loader: 'graphql-tag/loader'
      }

So I can import my graphql files now by....

import gql_query from './_query.graphql';
...
const ContainerWithMutations = compose(
  graphql(gql_query, {
    options: ({ selected }) => ({
      variables: { processId: selected},
    })
  })
)(Container);

@gaearon
Copy link
Contributor

gaearon commented Feb 8, 2017

Closing since we don't currently support any special integration with GraphQL without ejecting.

@gaearon gaearon closed this as completed Feb 8, 2017
@utkez
Copy link

utkez commented Feb 17, 2017

@anhdn there is an alternative version of relay-scripts with embedded Relay support, which does not require to eject: https://github.com/Valentin-Seehausen/create-react-app

@cezarneaga
Copy link

cezarneaga commented Mar 28, 2017

i am not sure about this but i got CRA to work with apollo without ejecting. is it not supposed to work? i dont think to have done anything special. server on :4000 client on :3000

@waliurjs
Copy link

@cezarneaga Can you please share your implementation in a fork? Or, at least a Readme in a gist?

@cezarneaga
Copy link

it's a bit more, as i have auth there too and i am currently refactoring it but: https://github.com/cezarneaga/apollo-cra-authenticated
also, apollo team has a tutorial too on this

@tkvw
Copy link

tkvw commented Aug 23, 2017

Just a heads up: you can use react-app-rewired to configure graphql-tag to load .graphql files without ejecting from CRA. (https://github.com/timarney/react-app-rewired)

I created a package for use with react-app-rewire to make configuration easy:
https://github.com/tkvw/react-app-rewire-graphql-tag
Config comes down to:
config-overrides.js:

const rewireGqlTag = require('react-app-rewire-graphql-tag');

module.exports = function override(config, env) {
    config = rewireGqlTag(config,env);    
    return config;
}

@shendepu
Copy link

CRA does not expose a way to extend webpack config. But here is a hack way to do it. The basic idea is to change the webpack config file in node_modules/react-scripts/config/ by

  1. move the node_modules/react-scripts/config/webpack.config.dev.js to node_modules/react-scripts/config/webpack.config.dev.origin.js,
  2. create a custom config that export function webpackConfig => webpackConfig in app config/webpack.config.dev.js
  3. create a node_modules/react-scripts/config/webpack.config.dev.js which content is simply import webpack.config.dev.origin.js and pass it through config/webpack.config.dev.js, and export the result.

So I wrote a simple extentConfig helper to do above operation
app/scripts/lib/extendConfig.js

const fs = require('fs')
const fse = require('fs-extra')
const path = require('path')

const appDirectory = fs.realpathSync(process.cwd())
function resolveApp(relativePath) {
  return path.resolve(appDirectory, relativePath)
}

function getFileStat(absolutePath) {
  try {
    return fs.statSync(absolutePath)
  } catch (e) {
    if (e.code === 'ENOENT') return null
    throw e
  }
}

function getConfig(webpackEnv, type) {
  if (!type) return resolveApp('./node_modules/react-scripts/config/webpack.config.' + webpackEnv + '.js')
  if (type === 'my') return resolveApp('./config/webpack.config.' + webpackEnv + '.js')

  return resolveApp('./node_modules/react-scripts/config/webpack.config.' + webpackEnv + '.' + type + '.js')
}

function extendConfig(webpackEnv, callback) {
  if (webpackEnv !== 'dev' && webpackEnv !== 'prod') {
    console.error('Only dev and prod is supported')
    return
  }

  return (
    moveAsOrigin(webpackEnv)
      .then(() => createWebpackConfig(webpackEnv))
      .then(() => callback())
  )
}

function moveAsOrigin(webpackEnv) {
  const webpackConfig = getConfig(webpackEnv)
  const webpackConfigOrigin = getConfig(webpackEnv, 'origin')
  const originStat = getFileStat(webpackConfigOrigin)

  if (!originStat) {
    return fse.move(webpackConfig, webpackConfigOrigin)
  } else {
    return Promise.resolve()
  }
}

function createWebpackConfig(webpackEnv) {
  const webpackConfig = getConfig(webpackEnv)
  const stat = getFileStat(webpackConfig)
  if (!stat) {
    return fse.outputFile(
      webpackConfig,
      `const config = require('./webpack.config.${webpackEnv}.origin')
const customConfigFunc = require('../../../config/webpack.config.${webpackEnv}')

module.exports = customConfigFunc(config)  
    `
    )
  }
}

module.exports = extendConfig

app/scripts/start.js

const extendConfig = require('./lib/extendConfig')

extendConfig('dev', () => {
  const start = require('react-scripts/scripts/start')
})

config/webpack.config.dev.js

module.exports = config => {
  const oneOfRules = config.module.rules.find(r => !!r.oneOf)
  const fileLoaderRule = oneOfRules.oneOf.find(r => r.loader && r.loader.includes('/file-loader/'))

  fileLoaderRule.exclude.push(/\.(graphql|gql)$/)

  config.module.rules.push({
    test: /\.(graphql|gql)$/,
    exclude: /node_modules/,
    loader: 'graphql-tag/loader',
  })
  return config
}

And it is similiar to extend webpack.config.prod.js by extendConfig('prod').

With this hack way, the all of packages, config and scripts ejected go away, and easy to upgrade along with react-scripts.

And in this way, you can extend any webpack config as you want.

@spsoto
Copy link

spsoto commented Feb 15, 2018

@shendepu thank you so much for this workaround. I think this is the way to go for tweaking the settings of CRA ATM, not just for the sake of using GraphQL.

@brycereynolds
Copy link

brycereynolds commented Aug 23, 2018

Yet another way is to use patch-package, edit the configs as mentioned by @tobkle and save the patch.

Here is the result of my patch against [email protected].

patch-package
--- a/node_modules/react-scripts/config/webpack.config.dev.js
+++ b/node_modules/react-scripts/config/webpack.config.dev.js
@@ -213,6 +213,13 @@ module.exports = {
               },
             ],
           },
+          {
+            test: /\.(graphql|gql)$/,
+            include: paths.appSrc,
+            exclude: /node_modules/,
+            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.
@@ -223,7 +230,16 @@ module.exports = {
             // its runtime that would otherwise processed through "file" loader.
             // Also exclude `html` and `json` extensions so they get processed
             // by webpacks internal loaders.
-            exclude: [/\.(js|jsx|mjs)$/, /\.html$/, /\.json$/],
+            // exclude: [/\.(js|jsx|mjs)$/, /\.html$/, /\.json$/],
+            exclude: [
+              /\.html$/,
+              /\.(js|jsx|mjs)$/,
+              // /\.css$/,
+              /\.json$/,
+              // /\.svg$/,
+              /\.graphql$/,
+              /\.gql$/
+            ],
             loader: require.resolve('file-loader'),
             options: {
               name: 'static/media/[name].[hash:8].[ext]',
--- a/node_modules/react-scripts/config/webpack.config.prod.js
+++ b/node_modules/react-scripts/config/webpack.config.prod.js
@@ -239,6 +239,13 @@ module.exports = {
             ),
             // Note: this won't work without `new ExtractTextPlugin()` in `plugins`.
           },
+          {
+            test: /\.(graphql|gql)$/,
+            include: paths.appSrc,
+            exclude: /node_modules/,
+            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
@@ -249,7 +256,16 @@ module.exports = {
             // it's runtime that would otherwise processed through "file" loader.
             // Also exclude `html` and `json` extensions so they get processed
             // by webpacks internal loaders.
-            exclude: [/\.(js|jsx|mjs)$/, /\.html$/, /\.json$/],
+            // exclude: [/\.(js|jsx|mjs)$/, /\.html$/, /\.json$/],
+            exclude: [
+              /\.html$/,
+              /\.(js|jsx|mjs)$/,
+              // /\.css$/,
+              /\.json$/,
+              // /\.svg$/,
+              /\.graphql$/,
+              /\.gql$/
+            ],
             options: {
               name: 'static/media/[name].[hash:8].[ext]',
             },

@lock lock bot locked and limited conversation to collaborators Jan 18, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests