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

Use Relay #462

Closed
lukejagodzinski opened this issue Aug 18, 2016 · 53 comments
Closed

Use Relay #462

lukejagodzinski opened this issue Aug 18, 2016 · 53 comments

Comments

@lukejagodzinski
Copy link

Hi, is it possible to use Relay with create-react-app without ejecting project and messing with webpack configuration?

I get the following error in the console:

invariant.js:38 Uncaught Invariant Violation: RelayQL: Unexpected invocation at runtime. Either the Babel transform was not set up, or it failed to identify this call site. Make sure it is being used verbatim as `Relay.QL`.

I was looking for solution and it seems to be problem with lack of Relay.QL transpiler in the Babel configuration. But all these projects were not created with create-react-app cli. From what I know it's not possible to mess with webpack configuration until I eject a project.

@lacker
Copy link
Contributor

lacker commented Aug 18, 2016

You can't add more transpilation steps without ejecting, so right now I think the answer is no. It would be nice if you could use Relay without ejecting, somehow, though.

@lukejagodzinski
Copy link
Author

lukejagodzinski commented Aug 18, 2016

Ok thanks for information. Do you know how to add such configuration to ejected project? Do you have some link to tutorial/guide how to do it?

@gaearon
Copy link
Contributor

gaearon commented Aug 18, 2016

We could detect if you have relay in package.json and add its Babel plugin. Since it’s part of the Facebook stack it makes sense to me to provide an integrated experience (as long as it works great).

@lukejagodzinski
Copy link
Author

@gaearon that would be great!

@lukejagodzinski
Copy link
Author

In the meantime does anyone know how to configure webpack after ejecting to work with Relay?

@schickling
Copy link

I think the solution @gaearon would make a lot of sense!

@jagi in the meanwhile you can eject and use a setup like in this example which uses babel-plugin-react-relay. It uses Relay's babel-relay-plugin internally but makes usage more convenient and extends its functionality. For example you no longer need to have a build/babelRelayPlugin.js script.

Let me know if you need any help setting it up.

@saintsjd
Copy link

saintsjd commented Aug 27, 2016

@gaearon thinking about writing a pull request for your idea above "detect if you have relay in package.json and add its Babel plugin"

Question though. The babelRelayPlugin needs a reference to a schema.json file (example here https://github.com/relayjs/relay-starter-kit/blob/master/build/babelRelayPlugin.js). This file is typically generated by a script that introspects a graphql server and saves the output to schema.json. What is the the cleanest way to handle this in a pull request to add realyjs support to create-react-app?

More explanation is found here https://facebook.github.io/relay/docs/guides-babel-plugin.html#content.

We could configure babelRelayPlugin to look for my-app/schema.json and write instructions in the README for the user on how he/she can create schema.json.

Additionally we could provide an npm run updateRelaySchema <url-to-your-graphql-server-here> which would introspect the graphql server and create my-app/schema.json.

Does this sound reasonable? Other ideas?

@schickling
Copy link

@saintsjd I think it makes a lot of sense in order to simplify this process further. What do you think of a workflow like proposed here: https://github.com/graphcool/graphql-config

@saintsjd
Copy link

@schickling Nice suggestion! I will try it.

@gaearon
Copy link
Contributor

gaearon commented Aug 28, 2016

cc @josephsavona, I expect the setup will be different in Relay 2?
Since it is preferred for new projects, is there anything we can do on our side to integrate better?

@josephsavona
Copy link

The setup in Relay2 will be basically the same - a single babel plugin that requires access to the schema. So it seems like implementing support would involve:

  • A way to detect if the user wants to use Relay (sounds like checking for react-relay in package.json would work)
  • A way to configure the GraphQL endpoint. graphql-config has potential here, though it seems best to advocate a single canonical place to store graphql config data. The default approach of graphql-config, an environment variable, doesn't seem ideal here because it leaves no room for specifying authentication data. Since this is a React project, using the package.json variation seems sensible.
  • Actually enabling the plugin with the schema. https://github.com/graphcool/babel-plugin-react-relay has potential here, though I think we should consider just changing the default Relay plugin to have the same (more convenient) behavior. babel-plugin-react-relay really is more convenient to use, but because it wraps the official plugin it means we have to upgrade two packages in coordination on every release, one of which we don't own.

So overall, I'm inclined to say that we should change babel-relay-plugin to support the package.json configuration option of graphql-config, and use that for create-react-app.

@fson
Copy link
Contributor

fson commented Aug 30, 2016

@josephsavona This sounds like a good plan for babel-relay-plugin. Since you brought up the topic of releases, now I'm wondering how we could determine which version of babel-relay-plugin to use in create-react-app? When the user updates react-relay, also babel-relay-plugin needs to be updated. The Babel plugins are dependencies of react-scripts and therefore not controlled by the user.

Since we can look up the react-relay package version from package.json and babel-relay-plugin seems to always track its version, maybe we could use that information to choose the right plugin version. But depending on many versions babel-relay-plugindoesn't seem like a great idea. We could also always support only the latest version, but that would mean that each time we change the supported Relay version, it would be a breaking change to react-scripts and the users need to update Relay to use it?

@josephsavona
Copy link

josephsavona commented Aug 30, 2016

@fson Good points - I hadn't considered the plugin versioning aspect. Ideally the plugin would rarely have to change. Instead, the plugin can have a peer dependency on a separate module - the Relay2 compiler - that it delegates to. Then the developer can be in charge of updating the Relay and the compiler versions together (and Relay can have a peer dependency on the compiler to enforce compatible versions), and create-react-app can depend on the (infrequently changing) Relay plugin.

@saintsjd
Copy link

saintsjd commented Sep 2, 2016

I was studying the source for babel-relay-plugin a bit. If I am not mistaken, getBabelRelayPlugin accepts either a schema object or a function for its first argument.

See https://github.com/facebook/relay/blob/master/scripts/babel-relay-plugin/src/getBabelRelayPlugin.js#L35 and https://github.com/facebook/relay/blob/master/scripts/babel-relay-plugin/src/getBabelRelayPlugin.js#L245-L247

Perhaps we don't need to change babel-relay-plugin? Maybe we can create a plugins/babelRelayPlugin.js file like this:

var getbabelRelayPlugin = require('babel-relay-plugin');

var getGraphQLSchemaFromPackageJson = function() {
   // parse package.json and get graphql settings like graphql-config does
   // use fetch and introspectionQuery to get schema 
   // return schema object
}

module.exports = getbabelRelayPlugin(getGraphQLSchemaFromPackageJson);

Then enable the plugin if the user wants relay (react-relay is in package json):

{
  "passPerPreset": true,
  "presets": [
    {"plugins": ["./plugins/babelRelayPlugin"]},
    "react-native"
  ]
}

I haven't tried this yet.

@josephsavona
Copy link

@saintsjd yeah, that's roughly how it would be implemented, I think. The plugin changes are more due to the need to make release coordination easier.

@saintsjd
Copy link

saintsjd commented Sep 3, 2016

I am working on a pull request for this. But, instructions in CONTRIBUTING.md in the section Setting Up a Local Copy are not working. Any ideas?

Here is what I am doing...

git clone https://github.com/facebookincubator/create-react-app
cd create-react-app
npm install
cd global-cli
npm install
cd .. 
npm run create-react-app my-app

This gives an error

Installing packages. This might take a couple minutes.
Installing react-scripts from npm...

npm ERR! addLocal Could not install /Users/jonsaints/Dev/create-react-app/react-scripts-0.4.0.tgz
npm ERR! Darwin 15.3.0
npm ERR! argv "/Users/jonsaints/.nvm/versions/node/v4.4.7/bin/node" "/Users/jonsaints/.nvm/versions/node/v4.4.7/bin/npm" "install" "--save-dev" "--save-exact" "/Users/jonsaints/Dev/create-react-app/react-scripts-0.4.0.tgz"
npm ERR! node v4.4.7
npm ERR! npm  v2.15.8
npm ERR! path /Users/jonsaints/Dev/create-react-app/react-scripts-0.4.0.tgz
npm ERR! code ENOENT
npm ERR! errno -2
npm ERR! syscall open

npm ERR! enoent ENOENT: no such file or directory, open '/Users/jonsaints/Dev/create-react-app/react-scripts-0.4.0.tgz'
npm ERR! enoent This is most likely not a problem with npm itself
npm ERR! enoent and is related to npm not being able to find a file.
npm ERR! enoent 

npm ERR! Please include the following file with any support request:
npm ERR!     /Users/jonsaints/Dev/create-react-app/my-app/npm-debug.log
`npm install --save-dev --save-exact /Users/jonsaints/Dev/create-react-app/react-scripts-0.4.0.tgz` failed```

@saintsjd
Copy link

saintsjd commented Sep 3, 2016

I think I found a workaround.

diff --git a/tasks/clean_pack.sh b/tasks/clean_pack.sh
index 2d945d5..0eb1ba1 100755
--- a/tasks/clean_pack.sh
+++ b/tasks/clean_pack.sh
@@ -68,7 +68,7 @@ packname=`npm pack`

 # Now we can copy the package back.
 cd ..
-cp -f $clean_path/$packname ./
+cp -f $clean_path/$packname $initial_path/../
 cleanup

@gaearon
Copy link
Contributor

gaearon commented Sep 3, 2016

Oops, sorry, I broke this.

@gaearon
Copy link
Contributor

gaearon commented Sep 3, 2016

@saintsjd Should be fixed on master with #566.

@saintsjd
Copy link

saintsjd commented Sep 3, 2016

Thanks a ton @gaearon! Confirmed. The fix works great on my end.

@maxwell-oroark
Copy link

maxwell-oroark commented Sep 8, 2016

I'm helping @saintsjd with this pull request. We have the schema being generated successfully like this:

var getGraphQLSchemaFromPackageJson = function() {
   // parse package.json and get graphql settings like graphql-config does
   // use fetch and introspectionQuery to get schema 
   // return schema object
}

and we also have the babelRelayPlugin enabled with, I think, the right settings. But for some reason we are getting a failure to compile with webpack. The specific error is:

Failed to compile.

Error in ./src/index.js
Module build failed: AssertionError: missing path
    at Array.map (native)
    at Array.map (native)
 @ multi main

When we feed the babelRelayPlugin a string of Relay.QL it works fine but something in the build process is keeping babelRelayPlugin from receiving the Relay.QL fragments... any ideas why this might be?

@josephsavona
Copy link

@maxwell-oroark Hmm, that error isn't very helpful in narrowing down the problem. I don't recall (and can't find with github search) a "missing path" assertion in the plugin code, so it looks like maybe the error is coming from somewhere else. Does the error occur simply by enabling the plugin, or does enabling the plugin work so long as there are no Relay.QL tags?

@maxwell-oroark
Copy link

@josephsavona The error goes away when Relay.QL tags are removed.

@josephsavona
Copy link

@maxwell-oroark strange. Unfortunately the error doesn't give enough info that I can give much advice. If you can possibly run the code with a debugger that would be ideal, otherwise this may require digging in and adding manual console.log statements in order to narrow things down. Maybe start with some log statements in the Relay plugin just to see if it is initialized and at least called.

@saintsjd
Copy link

@maxwell-oroark and I have made progress. We have a working version of create-react-app that enables relay support when you have react-relay in your package.json file and have an environment variable GRAPHQL_URL.

We don't have error messages or nice instructions in the readme yet. We are working on those before making the pull request.

If you want to take a look you can see progress here: https://github.com/maxwell-oroark/create-react-app/tree/relay-support

@saintsjd saintsjd mentioned this issue Sep 16, 2016
@saintsjd
Copy link

saintsjd commented Sep 19, 2016

Merged with master. We now have eject support, nicer errors, and a great README.

Note the environment variable is changed to REACT_APP_ GRAPHQL_URL

#662

@fson
Copy link
Contributor

fson commented Sep 20, 2016

I talked with @schickling and we would like come up with a standard approach for specifying the GraphQL schema/endpoint that can also be adopted by create-react-app. I think one potential issue with the current package.json configuration suggested above is that it doesn't allow using a different server for production and development. I've opened an issue in graphql-config to discuss solutions for that: kamilkisiela/graphql-config#9

@josephsavona do you have some ideas about this from Relay point of view? I think it would be fantastic, if we can come up with a GraphQL configuration approach for that can be adopted in CRA, but also in the underlying tools like babel-relay-plugin eventually. I commented in the pull request about some difficulties in fetching the schema in a Babel plugin – is that something that you could see changing with Relay 2 though?

othane added a commit to othane/cata-front that referenced this issue Nov 4, 2016
since create-react-app does not yet support the babel relay plugin we
need to eject !!! ... although this might be coming to a repo near you
soon

facebook/create-react-app#462

but for now we have to eject, install babel-relay-plugin,
babel-plugin-react-relay, and "babel-preset-stage-0 (for some reason)
manually ... then for some other reason I cannot get the babelrc to run
from the package.json so I needed to add the .babelrc file and override
that

so now .babelrc should call babelRelayPlugin so we can compile the
queries etc in the transpile ... note this needs the schema so you need
to update the schema.json and schema.graphql files using the
getSchema.js util (maybe I should move all these into config? .. I kinda
want to keep the eject clean though)

btw the webkit-dev-server will only reload the schema if npm is
restarted so if you want to change the schema on the server side you
need to restart npm and call node ./getSchema.js in between to update
relay

also while I was ejecting I did some small tweaks to their scripts that
shit me to tears ... like clearing the screen on each build (I like
console output dam it) and starting the browser all the time
@dphaener
Copy link

To expand on @vdanchenkov comment, consider using a timestamp to only expire the cache when the schema.json file changes. This is working great for me:

query: {
  cacheDirectory: true,
  cacheIdentifier: fs.statSync('config/schema.json').mtime
}

@ivosabev
Copy link

ivosabev commented Dec 8, 2016

@dphaener Can you elaborate on your solutions, maybe paste a fuller example?

@witbybit
Copy link

Should we use relay-fullstack (https://github.com/lvarayut/relay-fullstack) instead if we want to use React with Relay? Lots of posts in this thread but I am still not sure how to use Relay with create-react-app. (I wish github had a tag for marking the correct answer similar to Stack Overflow.)

@ivosabev
Copy link

@nikhilag It is as simple as ejecting after install and editing your package.json. Of course you need to install the necessary Relay packages as you would usually do.

"babel": {
  "plugins": [
    "RELATIVE_PATH_TO/babelRelayPlugin"
  ],
  "presets": [
    "react-app"
  ]
},

@dphaener
Copy link

@ivosabev @nikhilag Sorry for the delay here. I've actually modified how I am doing this, so here's a more complete example.

Instead of relying on the timestamp of the 'schema.json', which would require that you manually update that file and restart the server, I'm using nodemon to run the create-react-app server. But I'm only watching files that would change my schema. You'll notice that I'm watching .rb files, because I'm using a Ruby GraphQL server, but the same would apply to a node server.

Here's my nodemon.json configuration file:

{
  "restartable": "rs",
  "verbose": true,
  "execMap": {
    "rb": "ruby"
  },
  "watch": [
    "../app/graphql/**/*"
  ],
  "events": {
    "restart": "touch .schema_stamp && osascript -e 'display notification \"App restarted due to:\n'$FILENAME'\" with title \"nodemon\"'"
  },
  "env": {
    "NODE_ENV": "development"
  },
  "ext": "rb"
}

I'm using an osascript to send a notification in my Mac, but it's not necessary. The important thing there is that we are touching the .schema_stamp file, which you will see later.

Here is the relevant part of my webpack config:

loaders: [
  {
    test: /\.(js|jsx)$/,
    include: paths.appSrc,
    loader: 'babel',
    query: {
      cacheDirectory: true,
      cacheIdentifier: fs.statSync('.schema_stamp').mtime
    }
  },
]

You'll notice here that I am now watching the timestamp of the .schema_stamp file that is referred to in nodemon.json file. This will invalidate the cache, and cause the new schema to be reloaded when nodemon restarts.

I'm also using babel-plugin-react-relay here, so configuring where to get your Relay schema can be done in several ways, as outlined here: https://github.com/graphcool/graphql-config.

In my case, it's in my package.json file:

  "graphql": {
    "request": {
      "url": "http://localhost:7000/graphql",
      "headers": {
        "Authorization": "Bearer <my_special_introspection_token>"
      }
    }
  }

That's pretty much all I had to do to get Relay going with Create React App. Now when I start my server, I just use nodemon to start the server script instead of just node and it works perfectly(mostly)!

P.S. This was all done after ejecting the app, BTW.

@valle-xyz
Copy link

If you want to stay unejected, you can also use https://github.com/Valentin-Seehausen/create-react-app.

It is basically a wrapper for the Relay Support PR #662, that was canceled. Feedback welcome, would be cool, if this made things easier.

@gaearon
Copy link
Contributor

gaearon commented Feb 24, 2017

Closing as we don't plan this to work out of the box, but I'm glad that there's a fork supporting it!

@gaearon gaearon closed this as completed Feb 24, 2017
smmoosavi added a commit to monkey-patches/monkey-react-scripts that referenced this issue Mar 13, 2017
@toobulkeh
Copy link

@gaearon why the change of heart?

@ivosabev
Copy link

This is quite unfortunate for Relay, that even FB's own tools don't support them, since it is just a matter of letting the user extend the Babel configuration.

@schickling
Copy link

I'm pretty sure that with the new version of Relay the tooling will become a lot more flexible. This should make this possible again without needing to fork CRA.

@lacker
Copy link
Contributor

lacker commented Mar 15, 2017

There are a bunch of people at Facebook interested in making create-react-app work more smoothly with Relay. The tricky thing right now is that there are a ton of improvements on Relay coming, and we're not sure whether/how that will change the getting-started experience. So I think we should wait for the next big Relay release and then take another hard look at this and see how we can make the Relay <-> React experience better.

@gaearon
Copy link
Contributor

gaearon commented Mar 16, 2017

since it is just a matter of letting the user extend the Babel configuration

We may come back to this, but now is not a good time, especially with all the ES modules churn (we're in the process of switching to Webpack 2, it has bugs, etc). We want to retain full control over Babel configuration to allow a guaranteed stable experience for all users. We may explore making Babel configurable once the dust settles a little bit.

@kenips
Copy link

kenips commented Mar 27, 2017

@gaearon how about reopening this and leaving it at the proposal state and documenting that this will not be considered until Relay 2 lands, so that we won't have another issue opened?

@witbybit
Copy link

witbybit commented Apr 7, 2017

I think a simple solution is needed here which works seamlessly with create-react-app without requiring to eject or get react-scripts from somewhere else. Given that create-react-app has gained so much popularity, I think people won't use Relay just because it is not straightforward to use it with create-react-app. I had to switch to Apollo (which is an excellent client as well) because I was running into issues with setting up Relay and I really didn't want to eject.

@gaearon
Copy link
Contributor

gaearon commented Apr 7, 2017

As mentioned above, Relay itself is changing significantly (Relay Classic => Relay Modern), and now is not a very good time to invest into a solution like this. I don’t think it makes sense to reopen because the churn is still there. Happy to reopen in half a year or so, but another issue might work better at that point.

@josephsavona
Copy link

Agree with @gaearon - let's reevaluate this once Relay Modern is officially open source. It would be great to either support Relay Modern officially within create-react-app, or to make it very easy for projects to build upon create-react-app (so that we could build a create-relay-app that tracked create-react-app and configured Relay).

@trevordmiller
Copy link

trevordmiller commented Apr 21, 2017

@gaearon @josephsavona Now that Relay Modern is out, would love to see Create React App add support without ejecting; looks like there is an open issue for this: #2001.

@josephsavona
Copy link

@trevordmiller The idea of create-react-app is meant as an easy way to get started with React; it isn't meant to cover every case. As the readme notes, "the feature set is intentionally limited" and the eject feature exists to support power users such as yourself who need additional configuration. I would hope that the need to eject wouldn't hold people back from trying Relay Modern (or, for that matter, from trying Apollo client and its Babel plugin!)

That said, it would be great to come up with some solution to make it easier for people using CRA to try out Relay Modern or any other framework that required an extra Babel plugin. @gaearon, do you have any thoughts on this?

@trevordmiller
Copy link

trevordmiller commented Apr 21, 2017

@josephsavona Thanks for your response. I understand and agree with the premise. But I'm wondering if a conditional feature could be added as has been done with yarn (when you have a yarn.lock it uses yarn instead of npm), flow (when you have a .flowconfig), Jest, etc. I've found great value in not ejecting so that I get all of the underlying react-scripts updates essentially for free. I understand not every tool can be conditionally supported, but since Relay is a facebook product like Yarn and Jest, to me it makes sense to have some sort of conditional support as the other facebook tools have in CRA. Anyways, just a thought :)

I did try out Relay Modern and am enjoying it. Thanks for the great work.

@arvinsim
Copy link

It's such a shame since I really want to try Relay Modern. Setting up Apollo in create-react-app was painless for me.

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

No branches or pull requests