Git Product home page Git Product logo

isomorphic-relay's People

Contributors

denvned avatar dylansale avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

isomorphic-relay's Issues

How to debug queries?

I get some errors on prepareData

{ [Error: fetchWithRetries(): Still no successful response after 1 retries, giving up.]
  response: 
   Body {
     url: 'http://localhost:4000/graph',
     status: 400,
     statusText: 'Bad Request',
     headers: Headers { _headers: [Object] },
     ok: false,
     body: 
      PassThrough {
        _readableState: [Object],
        readable: true,
        domain: null,
        _events: [Object],
        _eventsCount: 7,
        _maxListeners: undefined,
        _writableState: [Object],
        writable: true,
        allowHalfOpen: true,
        _transformState: [Object] },
     bodyUsed: false,
     size: 0,
     timeout: 0,
     _raw: [],
     _abort: false } }

I guess that is because 400 is returned from graphql endpoint. How I can get string representing query?
How you could debug this ?

Question: how do you flush relay store?

Hello!
In example we can see that relay instance lives in persistent scope.

Does it mean that query data will be cached in node memory and shared between requests?

Or does this line const storeData = RelayStoreData.getDefaultInstance(); create an empty instance for each request?

Authenticating with Isomorphic Relay

Hey, I've been using cookies for token-based authentication, as the source for my token.
To include the token automatically, I use the known fetch option:

const networkLayer = new Relay.DefaultNetworkLayer(GRAPHQL_URL, {
    credentials: 'same-origin',
});

This works great for the client which uses the regular fetch which uses this option. but server-side uses node-fetch which doesn't knows this option and doesn't send the cookies automatically. This causes to the cookies to be missing on my graphql-express middleware.

This is solvable using this ugly solution:

// The signle route which utilizes isomorphoic relay router etc...
app.get('*', (req, res, next) => {
  const networkLayer = new Relay.DefaultNetworkLayer(GRAPHQL_URL, {
    headers:{
      cookie: req.headers.cookie,
    },
  });

So basically every request I'm creating a new network layer with the cookies attached. Pretty ugly.

Nothing you can do really, but I guess it should be acknowleged.

Peer Dependencies

Any reason why Relay peer dependency is 0.8.0 || 0.9.0 and not ^0.8.0 || ^0.9.0?

I know there used to be a concern with the reliance on Relay internals, but at this point, aren't we safe to rely on minor version?

When webpack built: Invariant Violation: RelayQueryNode: Abstract class cannot be instantiated.

Hi, I saw issue #10 but since I'm not using decorators I didn't want to lead anyone astray.

I've started with the basic relay-starter-kit and worked my way from there. isomorphic-relay works fine with rehydration etc, until... I do a webpack build (Both webpack -p and webpack -d causes this problem).

My dev environment consists of running the server with babel-node and WDS as watch, whereas my production build transpiles the server files with babel and the routes file (The React application entry from isomorphic-relays perspective) as a CommonJS module.

It perhaps sounds more complex than it is, I can open the transpiled server files and just console.log the imported routes module and get the same results as in the dev environment so I don't see why there should be a difference.

Anyway, when I run the built server and visit a route which in the dev env will server-render without any problems, the application crashes with this stack trace:

/Users/oskar/src/my-relay-project/node_modules/react-relay/node_modules/fbjs/node_modules/promise/lib/done.js:10
      throw err;
      ^

Invariant Violation: RelayQueryNode: Abstract class cannot be instantiated.
    at invariant (/Users/oskar/src/my-relay-project/node_modules/react-relay/node_modules/fbjs/lib/invariant.js:38:15)
    at new RelayQueryNode (/Users/oskar/src/my-relay-project/node_modules/react-relay/lib/RelayQuery.js:107:93)
    at createNode (/Users/oskar/src/my-relay-project/node_modules/react-relay/lib/RelayQuery.js:1192:12)
    at /Users/oskar/src/my-relay-project/node_modules/react-relay/lib/RelayQuery.js:178:24
    at Array.forEach (native)
    at /Users/oskar/src/my-relay-project/node_modules/react-relay/lib/RelayQuery.js:174:28
    at RelayQueryRoot.getChildren (/Users/oskar/src/my-relay-project/node_modules/react-relay/lib/RelayQuery.js:186:9)
    at RelayQueryRoot.instrumentedCallback [as getChildren] (/Users/oskar/src/my-relay-project/node_modules/react-relay/lib/RelayProfiler.js:137:40)
    at RelayQueryRoot.hasDeferredDescendant (/Users/oskar/src/my-relay-project/node_modules/react-relay/lib/RelayQuery.js:261:67)
    at RelayQueryRoot.instrumentedCallback [as hasDeferredDescendant] (/Users/oskar/src/my-relay-project/node_modules/react-relay/lib/RelayProfiler.js:137:40)
    at RelayQueryRoot.hasDeferredDescendant (/Users/oskar/src/my-relay-project/node_modules/react-relay/lib/RelayQuery.js:482:81)
    at /Users/oskar/src/my-relay-project/node_modules/react-relay/lib/GraphQLQueryRunner.js:96:64
    at Array.forEach (native)
    at splitAndFlattenQueries (/Users/oskar/src/my-relay-project/node_modules/react-relay/lib/GraphQLQueryRunner.js:95:15)
    at /Users/oskar/src/my-relay-project/node_modules/react-relay/lib/GraphQLQueryRunner.js:177:5
    at /Users/oskar/src/my-relay-project/node_modules/react-relay/lib/RelayTaskQueue.js:118:25
    at /Users/oskar/src/my-relay-project/node_modules/react-relay/lib/RelayTaskQueue.js:124:15
    at RelayTaskQueue._invokeWithinScopedQueue (/Users/oskar/src/my-relay-project/node_modules/react-relay/lib/RelayTaskQueue.js:163:7)
    at /Users/oskar/src/my-relay-project/node_modules/react-relay/lib/RelayTaskQueue.js:153:14
    at RelayTaskQueue._scheduleIfNecessary (/Users/oskar/src/my-relay-project/node_modules/react-relay/lib/RelayTaskQueue.js:180:9)
    at RelayTaskQueue.enqueue (/Users/oskar/src/my-relay-project/node_modules/react-relay/lib/RelayTaskQueue.js:130:10)
    at Object.enqueue (/Users/oskar/src/my-relay-project/node_modules/react-relay/lib/RelayTaskScheduler.js:86:37)
    at runQueries (/Users/oskar/src/my-relay-project/node_modules/react-relay/lib/GraphQLQueryRunner.js:159:22)
    at GraphQLQueryRunner.forceFetch (/Users/oskar/src/my-relay-project/node_modules/react-relay/lib/GraphQLQueryRunner.js:82:12)
    at RelayContext.forceFetch (/Users/oskar/src/my-relay-project/node_modules/react-relay/lib/RelayContext.js:98:45)
    at /Users/oskar/src/my-relay-project/node_modules/isomorphic-relay/lib/prepareData.js:47:22
    at new Promise (/Users/oskar/src/my-relay-project/node_modules/babel-polyfill/node_modules/core-js/modules/es6.promise.js:197:7)
    at Promise.exports.(anonymous function).target.(anonymous function).function.target.(anonymous function).F (/Users/oskar/src/my-relay-project/node_modules/isomorphic-relay/node_modules/babel-runtime/node_modules/core-js/library/modules/_export.js:35:28)
    at Object.prepareData (/Users/oskar/src/my-relay-project/node_modules/isomorphic-relay/lib/prepareData.js:31:12)
    at Object.prepareData (/Users/oskar/src/my-relay-project/node_modules/isomorphic-relay-router/lib/prepareData.js:27:38)
    at /Users/oskar/src/my-relay-project/build/server/render.js:37:49
    at /Users/oskar/src/my-relay-project/node_modules/react-router/lib/match.js:65:5
    at /Users/oskar/src/my-relay-project/node_modules/react-router/lib/createTransitionManager.js:117:11
    at done (/Users/oskar/src/my-relay-project/node_modules/react-router/lib/AsyncUtils.js:81:19)

I perform the render from the server through this module:

import React from 'react';
const { routes } = require('../front/routes');
import { renderToString } from 'react-dom/server';
import { match } from 'react-router';
import IsomorphicRouter from 'isomorphic-relay-router';

export default function render(networkLayer, location) {
    return new Promise((resolve, reject) => {
        match({ routes, location }, (error, redirectLocation, renderProps) => {
            if (error) {
                reject(error);
            } else if (redirectLocation) {
                resolve({
                    status: 301,
                    from: location,
                    location: redirectLocation.pathname + redirectLocation.search,
                });
            } else if (renderProps) {
                IsomorphicRouter.prepareData(renderProps, networkLayer)
                    .then(({ data, props }) => {
                        const reactOutput = renderToString(
                            <IsomorphicRouter.RouterContext { ...props } />
                        );

                        resolve({
                            status: 200,
                            reactOutput,
                            preloadedData: JSON.stringify(data),
                        });
                    })
                    .catch(err => {
                        reject(err);
                    });
            } else {
                resolve({
                    status: 404,
                    from: location,
                });
            }
        });
    });
}

I know it's a lot to swallow, but do you have any pointers on where to look? Thanks!

Support for Relay v0.9.0

At this point this is more of a question, as with every other upgrade of Relay. Would you suggest that a new version of isomorphic-relay is necessary, or the current version should be compatible?

Network Layer making multiple requests in NodeJS

I have an app using isomorphic-relay and isomorphic-relay-router. When I render my containers on the client, Relay is batching the queries into one network request but when I render the same hierarchy of containers on the server, the queries are split into multiple requests. Is this by design, a limitation in isomorphic-relay or potentially a bug in my code?

passport.js req.user issue on SSR

I used to identify a user by passport.js with express-session and a req.user (with passport..session enhancement) is needed in GraphQL schema resolve function, which to identify the current user. it works fine in client relay query with credentials: 'same-origin' in Relay NetworkLayer,.
But on server side, the prepareData function seems to receive no req object?
Any solution to this?
Or better solution to identify the current user?

Thanks for your time.
:simple_smile:

DONE by adding header on server side relay networklayer same as #53

Why is prepareInitialRender async?

First of all, thanks for the amazing work ๐Ÿ‘

I'm trying to integrate this project with next.js, but I'm struggling with rehydrating in the client. Unfortunately in next.js the render funciton is sync (just like in React). There is an async fn called getInitialProps to collect data, but that is only called server-side or on page transition.

So I looked into rehydrating Relay in the render fn (https://github.com/Gregoor/next.js-relay-example/blob/9ee954a8f6449d1891ae546799c1bc0e564d55aa/pages/index.js#L62), but since prepareInitialRender is async, that won't really work. So I was wondering what the reason behind it is, since theoretically all the data is already there, right? Is it that there is simply no Relay API to get the initial render props synchronously?

Multiple injectPreparedData issue

I am passing two sets of data to two separate calls to injectPreparedData in one view, like so:

IsomorphicRelay.injectPreparedData(relayInfinite);
IsomorphicRelay.injectPreparedData(relayBreaker);

...yet I am seeing the following error:
image

All works (on server and client) when I only call injectPreparedData once on one set of relay data, like so:

IsomorphicRelay.injectPreparedData(relayInfinite);

I also tried merging both sets of data and calling injectPreparedData once, like so:

IsomorphicRelay.injectPreparedData([...relayInfinite, ...relayBreaker]);

...but then I still get the Uncaught TypeError: dataID.substring is not a function error, as above.

Package affected by Babel 6 inheritance bug.

This package (as well as isomorphic-relay-router) currently doesn't work in IE due to a very serious inheritance bug in Babel 6.

The class IsomorphicRenderer doesn't define a default constructor, so one is made for it:

        function IsomorphicRenderer() {
            (0, _classCallCheck3.default)(this, IsomorphicRenderer);
            return (0, _possibleConstructorReturn3.default)(this, (0, _getPrototypeOf2.default)(IsomorphicRenderer).apply(this, arguments));
        }

The idea of this default constructor is to call the parent class's constructor. However, this does not work (because IE<10 lacks __proto__?), though.

The current workaround is to vendor the module (as opposed to using npm install) and use babel 5 to compile it.

Invariant Violation when using a decorator

I'm getting this: Invariant Violation: RelayQueryNode: Abstract class cannot be instantiated. when I attempt to wrap my React component with a decorator. Example:

var relayDecorator = function(component) {
  return Relay.createContainer(component, { fragments: component.fragments })
}

@relayDecorator
export default class Component extends React.Component {
  ...
}

A couple of things to note here. I originally thought this was a Relay and/or Babel 6 issue, but in an attempt to recreate it on a smaller scale (the full blown code that I'm using is in a private project), everything worked fine as long as I wasn't server rendering. As soon as I introduced isomorphic-relay, I started getting these errors.

Thanks for the library btw, I'm loving it so far!

Can this somehow be used with react-rails

I have an isomorphic application using react-router and react-rails and it works fine (both server and client). Now I'm starting to use Relay and obviously I cannot render it on the server (it uses timeout, etc). I don't use anywhere preparedata or match so not sure how to apply this or isomorphic-relay-router...
Thanks

React render not resolving the diff in server vs. client graphql response

Hi, I've got isomorphic-relay working nicely. I am finding however, that while the component renders in the html payload from the server, that when the relay query subsequently runs in the client, it triggers a re-render...effectively removing the server markup from the dom and replacing it with the result from the client, even though they are essentially the same. Do you have any help or pointers on how to avoid this needless resolution of a diff (that should be a "non-diff") in the vdom?

Bundling webpack with IsomorphicRelay

I am using isomorphic relay and integrated webpack for the node server with babel and the relay-babel-plugin. It all works well when I load the page the first time, the second one it crashes with the following error.

ReferenceError: document is not defined
    at getActiveElement (/Users/AJ/Desktop/winebox/app/build/index.js:17061:13)
    at ReactReconcileTransaction.ReactInputSelection.getSelectionInformation (/Users/AJ/Desktop/winebox/app/build/index.js:16650:24)
    at ReactReconcileTransaction.Mixin.initializeAll (/Users/AJ/Desktop/winebox/app/build/index.js:4477:76)
    at ReactReconcileTransaction.Mixin.perform (/Users/AJ/Desktop/winebox/app/build/index.js:4444:13)
    at ReactUpdatesFlushTransaction.Mixin.perform (/Users/AJ/Desktop/winebox/app/build/index.js:4445:21)
    at ReactUpdatesFlushTransaction.assign.perform (/Users/AJ/Desktop/winebox/app/build/index.js:3677:39)
    at Object.flushBatchedUpdates (/Users/AJ/Desktop/winebox/app/build/index.js:3738:20)
    at Object.wrapper [as flushBatchedUpdates] (/Users/AJ/Desktop/winebox/app/build/index.js:3983:22)
    at ReactDefaultBatchingStrategyTransaction.Mixin.closeAll (/Users/AJ/Desktop/winebox/app/build/index.js:4511:26)
    at ReactDefaultBatchingStrategyTransaction.Mixin.perform (/Users/AJ/Desktop/winebox/app/build/index.js:4458:17)

I have it narrowed down to the portion that creates the reactOutput in the render function.

const reactOutput = ReactDOMServer.renderToString(
      <IsomorphicRelay.RootContainer {...rootContainerProps} />
    );

Is there a way to fix this? Thanks in advance for any help

Make fixFetch patch optional

Hi!

I use webpack to build my server, and the fixFetch patch is not needed in if alias is used. In fact, when using them together it throws some warnings for Failed Context Types on the server render.

What do you think of making the fixFetch patch optional? It could be used explicitly before requiring anything else:

require('isomorphic-relay/patchFetch');
import Relay from 'react-relay';
import IsomorphicRelay from 'isomorphic-relay';

or have the default export without the patch and a second one with the patch:

import IsomorphicRelay from 'isomorphic-relay/patchedFetch';
import Relay from 'react-relay';

or the other way around:

import Relay from 'react-relay';
import IsomorphicRelay from 'isomorphic-relay/unpatchedFetch';

Do you like the idea? I could help with a PR if you help pick one of the options 8) . I like the first one.

Getting 'Encountered error: "ReferenceError: self is not defined"'

I know this error is supposed to come from relay on the server side, and that IsomorphicRelay is supposed to have some hack to work around it, but I'm actually getting this error as soon as I add

import IsomorphicRelay from 'isomorphic-relay';

even without importing relay itself. Working with the most recent version from npm - 0.4.2
If I remove the IsomorphicRelay import the error goes away (but obviously I do need it as I'm trying to play with relay and server side rendering).

If it helps at all, the first few lines of the server side js bundle are:

/******/ (function(modules) { // webpackBootstrap
/******/        // The module cache
/******/        var installedModules = {};

/******/        // The require function
/******/        function __webpack_require__(moduleId) {

/******/                // Check if module is in cache
/******/                if(installedModules[moduleId])
/******/                        return installedModules[moduleId].exports;

/******/                // Create a new module (and put it into the cache)
/******/                var module = installedModules[moduleId] = {
/******/                        exports: {},
/******/                        id: moduleId,
/******/                        loaded: false
/******/                };

/******/                // Execute the module function
/******/                modules[moduleId].call(module.exports, module, module.ex
ports, __webpack_require__);

/******/                // Flag the module as loaded
/******/                module.loaded = true;

/******/                // Return the exports of the module
/******/                return module.exports;
/******/        }


/******/        // expose the modules object (__webpack_modules__)
/******/        __webpack_require__.m = modules;

/******/        // expose the module cache
/******/        __webpack_require__.c = installedModules;

/******/        // __webpack_public_path__
/******/        __webpack_require__.p = "/webpack/";

/******/        // Load entry module and return exports
/******/        return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {

        'use strict';

        var _isomorphicRelay = __webpack_require__(232);

        var _isomorphicRelay2 = _interopRequireDefault(_isomorphicRelay);

        var _reactOnRails = __webpack_require__(1);

        var _reactOnRails2 = _interopRequireDefault(_reactOnRails);

        function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

        var stringify = __webpack_require__(447);

        var React = __webpack_require__(171);

Uncaught TypeError: Cannot read property 'id' of undefined in getConfigs()

schema file:

var GraphQL = require('graphql')
var GraphQLRelay = require('graphql-relay')


const STORY = {
  comments: [],
  id: '42',
};

var CommentType = new GraphQL.GraphQLObjectType({
  name: 'Comment',
  fields: () => ({
    id: {type: GraphQL.GraphQLID},
    text: {type: GraphQL.GraphQLString},
  }),
});

var StoryType = new GraphQL.GraphQLObjectType({
  name: 'Story',
  fields: () => ({
    comments: { type: new GraphQL.GraphQLList(CommentType) },
    id: { type: GraphQL.GraphQLString },
  }),
});

var CreateCommentMutation = GraphQLRelay.mutationWithClientMutationId({
  name: 'CreateComment',
  inputFields: {
    text: { type: new GraphQL.GraphQLNonNull(GraphQL.GraphQLString) },
  },
  outputFields: {
    story: {
      type: StoryType,
      resolve: () => STORY,
    },
  },
  mutateAndGetPayload: (text) => {
    var newComment = {
      id: STORY.comments.length,
      text,
    };
    STORY.comments.push(newComment);
    return newComment;
  },
});

module.exports = new GraphQL.GraphQLSchema({
  query: new GraphQL.GraphQLObjectType({
    name: 'Query',
    fields: () => ({
      story: {
        type: StoryType,
        resolve: () => STORY,
      },
    }),
  }),
  mutation: new GraphQL.GraphQLObjectType({
    name: 'Mutation',
    fields: () => ({
      createComment: CreateCommentMutation,
    }),
  }),
});

compoent file

var React = require('react') // eslint-disable-line no-unused-vars
var ReactDOM = require('react-dom')
var Relay = require('react-relay') // eslint-disable-line no-unused-vars


Relay.injectNetworkLayer(
  new Relay.DefaultNetworkLayer('http://localhost:3000/graphql', {
    headers: {
      'Content-Type': 'application/json',
    },
  })
);



class CreateCommentMutation extends Relay.Mutation {
  static fragments = {
    story: () => Relay.QL`
      fragment on Story { id }
    `,
  };
  getMutation() {
    return Relay.QL`
      mutation{ createComment }
    `;
  }
  getFatQuery() {
    return Relay.QL`
      fragment on CreateCommentPayload { 
        story { comments },
      }
    `;
  }
  getConfigs() {
    return [{
      type: 'FIELDS_CHANGE',
      fieldIDs: { story: this.props.story.id},
    }];
  }
  getVariables() {
    return { text: this.props.text };
  }
}

class Comment extends React.Component {
  render() {
    var {id, text} = this.props.comment;
    return <li key={id}>{text}</li>;
  }
}
Comment = Relay.createContainer(Comment, {
  fragments: {
    comment: () => Relay.QL`
      fragment on Comment {
        id,
        text,
      }
    `,
  },
});

class Story extends React.Component {
      constructor(props) {
        super(props);
        this._handleSubmit = this._handleSubmit.bind(this);
  }

  _handleSubmit(e){
    e.preventDefault();
      Relay.Store.commitUpdate(
      new CreateCommentMutation({
        story: this.props.story,
        text: this.refs.newCommentInput.value,
      })
    );
    this.refs.newCommentInput.value = '';
  }

  render() {
    var {comments} = this.props.story;
    return (
      <form id="myform" action="" onSubmit={this._handleSubmit}>
        <h1>Breaking News</h1>
        <p>The peanut is neither a pea nor a nut.</p>
        <strong>Discuss:</strong>
        <ul>

         { comments.map(function(comment,index) {

                    return <Comment key ={index} comment={comment} />
                   })
                }
        </ul>
        <input
          placeholder="Weigh in&hellip;"
          ref="newCommentInput"
          type="text"
        />
      </form>
    );
  }
}

export default Relay.createContainer(Story, {
  fragments: {
    story: () => Relay.QL`
      fragment on Story {
        comments {
          ${Comment.getFragment('comment')},
        },
        ${CreateCommentMutation.getFragment('story')},
      }
    `,
  },
});

Differences between Relay.Renderer and IsomorphicRelay.Renderer

Thank you for the excellent work on isomorphic-relay and isomorphic-relay-router

I am trying to understand how the implementation of IsomorphicRelay.Renderer is different to Relay.Renderer.

  • They both wrap RelayReadyStateRenderer which is a private api (it's not mentioned in the docs)
  • IsomorphicRelay.Renderer is not rendering the initial loading screen to prevent duplicate renderings on the server
  • Relay.Renderer is referencing the Garbage Collector and implements other things that IsomorphicRelay.Renderer doesn't implement (I am not familiar enough with Relay to know what these things do).

Are there any known inconsistencies/limitations in using IsomorphicRelay.Renderer in place of Relay.Renderer?

I can tell from the history of the relay repo that there has been previous attempts to make Relay.Renderer isomorphic. This makes me think that isomorphic-relay is a stepping stone to native isomorphic rendering in relay. Is this correct? If so, are there current blockers to make this happen?

injectPreparedData on the server side?

Can prepareData accept on optional environment so that injectPreparedData can be called on the server side if some data is known to already be available, such as from an upstream service?

If not provided, environment can still default to new Relay.Environment().

If this seems like a reasonable approach, I can make a PR.

Question: Parse session in graphql

Hello, I'm creating a basic user authentication with server side rendering...

My server looks like this

https://github.com/jkettmann/relay-authentication/blob/master/server/server.js

where graphqlServer:
https://github.com/jkettmann/relay-authentication/blob/master/server/graphQlServer.js

i have also appended a render function in the server.js file:

const networkLayer = new Relay.DefaultNetworkLayer(GRAPHQL_URL,{
    credentials: 'same-origin',
    session: req.session
  });

  match({ routes:routes({req.context}), location: req.url }, async (error, redirectLocation, renderProps) => {
    if (error) {
      next(error);
    } else if (redirectLocation) {
      res.redirect(302, redirectLocation.pathname + redirectLocation.search);
    } else if (renderProps) {
      await fetchData(renderProps, req.context)
      IsomorphicRouter.prepareData(renderProps, networkLayer).then(render).catch(next);
    } else {
      res.status(404).send('Not Found');
    }

Now, when I refresh the page, I got in the graphql server an empty session and then it creates an anonymous token.

But, if I go in a page, that needs data from relay, without page reload then I get the session with the logged in user token.

It seems like that injecting the session in networkLayer doesn't work...

What is my fault?

Question: suitable for usage within a hapi + fluxible based app

I am working with this repo in the context of a hapi app with fluxible, and am finding that the examples in examples/star-wars are very centered on express. Are you aware of any pitfalls in adapting this work for such usage? I'm happy to share anything I learn along the way, as well!

How to load data for a RootContainer supplied to Router on server side?

I pass a RootContainer with a Relay.Route supplied to it in the isomorphic-relay-router. This root container contains other RootContainers with different Relay.Routes in the component supplied to it. For a complete server side rendering I would like all the data for the RootContainer supplied to router and RootContainers loaded by the component in the supplied RootContainer to be loaded server side.

I read somewhere in the comments that IsomorphicRelay.Renderer should be used in place of the default Relay.Renderer. I can replace the RootContainers with isomorphic renderers. Will it solve the problem? The renderer needs an environment as argument which is different server and client side. How can I effectively use the same renderer while passing in different environments? The problem is particularly serious on server side. I can't create a global variable. So there should be a way to pass the environment created on renderOnServer.js to the IsomorphicRenderer I use in place of RootContainer. this.context.relay is undefined when passed as environment to the renderer.

Expected prop to be data fetched by Relay

Hi, after i upgraded to isomorphic-relay v0.5.1 All my components started to complain asking that the data has to be data fetched by relay.

Warning: RelayContainer: Expected propmesupplied toNavbarto be data fetched by Relay. This is likely an error unless you are purposely passing in mock data that conforms to the shape of this component's fragment.

screen shot 2016-02-15 at 22 40 18

Any idea about this? After hours of debugging still i couldn't find the reason

Webpack integration

Hi @denvned and thanks for your work on this very needed Relay feature.

I have successfully integrated isomorphic-relay and isomorphic-relay-router into my project. However, my webpack build process is now broken. I have to manually transpile the code before running it. Which makes sense, since the babelRelayPlugin is used to transform Relay.QL fragments on the client and not on the server.

I get this error,

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`.

Have you found anyway to run the babelRelayPlugin transformation when rendering on the server and integrating that with webpack?

facebook/relay#589

Problem with preloaded queries which use Enum and mutations

I'm not sure whether this is a problem with isomorphic-relay, isomorphic-relay-router, or just my fault, but I have very weird problem, and it would probably be hard to explain.

I'll start with some information on my application:

I have 2 routes, say A and B, which queries a list of polls which can be sorted according to the input Enum: which accepts either TOP, TRENDING or NEW.
I also implemented a mutation which creates a poll, which can be accessed on a different route - C.
let's say I open my browser and open my app, it starts with route A, my index Route. The servers loads the polls fine, and the data is injected on the client. cool!

now I go to route C and try to create a poll, I click submit and I see this (console.log the transaction on the mutation's onFailure cb):
capture

and on Network this:

{"errors":[{"message":"Argument \"orderBy\" has invalid value \"TRENDING\".\nExpected type \"PollSort\", found \"TRENDING\".","locations":[{"line":32,"column":29}]}]}

I've looked on the query and this is what my application sent: (the relevant part is on fragment F1)

mutation CreatePollMutation($input_0:CreatePollInput!) {
  createPoll(input:$input_0) { 
    clientMutationId, 
    ...F7, 
    ...F9, 
    ...Fa 
  } 
} 

fragment F0 on Poll { 
  id, 
  title, 
  options, 
  _voteslie3m:votes(first:10) { 
    edges { 
      node { 
        option, 
        id 
      }, 
      cursor 
    }, 
    pageInfo { 
      hasNextPage, 
      hasPreviousPage 
    } 
  }, 
  author { 
    id, 
    username 
  } 
} 

fragment F1 on Store { 
  _pollsGboKo:polls(orderBy:"TRENDING",first:4) {  //should be just TRENDING without " "
    edges { 
      node { 
        id, 
        ...F0 
      }, 
      cursor 
    }, 
    pageInfo { 
      hasNextPage, 
      hasPreviousPage 
    } 
  }, 
  id 
} 

fragment F2 on Store { 
  id, 
  pollCount 
}

fragment F3 on Store { 
  id,
  ...F2 
} 

fragment F4 on User { id } 

fragment F5 on User { id, pollCount } 

fragment F6 on User { id, ...F5 } 

fragment F7 on CreatePollPayload { 
  store { id, ...F1, id, ...F3 }, 
  viewer { id, ...F4, id, id, id, ...F6 } 
} 

fragment F8 on Store { id } 

fragment F9 on CreatePollPayload { 
  pollEdge { 
    cursor, 
    __typename, 
    node { 
      id, 
      title, 
      options, 
      _voteslie3m:votes(first:10) { 
        edges { 
          node { 
            option, 
            id 
          }, 
          cursor 
        }, 
        pageInfo {
          hasNextPage, 
          hasPreviousPage
        } 
      }, 
      author {id, username } 
    } 
  },
  store { id, ...F8, id, ...F3 } 
} 

fragment Fa on CreatePollPayload { 
  pollEdge { 
    cursor, 
    node { id } 
  }
}

take note that F1 is a fragment which route A component's container requires. Somehow it passes as a string when I create a mutation.

2 things important to know:

  1. If I open the browser directly to route C or any route which isn't A and B (that uses this Enum), and then go to C and try to create a poll - everything works! this is why I doubt the problem is with me.
  2. If I break the "isomorphication" of my app by changing
// data is JSON.parse(...preloadedData...);
IsomorphicRelay.injectPreparedData(environment, data);

to:

IsomorphicRelay.injectPreparedData(environment, []);

The problem disappears.

Any ideas? Is it something I'm doing wrong?

Why does Relay sometimes prefix query keys with underscores and random strings?

Forgive me if this should be posted in the Relay repo, but since this has to do with data before its sent over to the client I figured I would post here first.

So I'm trying to get response information from a Relay request before its sent over to the client, but occasionally, when inspecting the response object, it looks like there's some kind of reconciliation going on where Relay prefixes my object keys with an _ and a random string, e.g., _user3fdg.

For example, given this dummy query:

export default {
  viewer: (component, params) => Relay.QL`
    query {
      viewer {
        sale(id: "los-angeles-modern-auctions-march-2015") {
          name
        }
        sales {
          id
          sale_artworks {
            id
          }
        }
     }
  }
}

Returns this response:

...

IsomorphicRelay.prepareData(renderProps, networkLayer).then(({ data }) => {
  console.log(data)
})

screen shot 2017-02-06 at 9 53 36 pm

Notice the strange _saleti0VC key thats being passed back (I'm expecting just sale), while the sales key seems correct? This makes it impossible to deterministically grab data from a response to perform side-effects server-side before the data on the server is sent to the client.

What I would expect is that once IsomorphicRelay.prepareData returns its data response that it is the final representation that is rehydrated on the client, but unfortunately that's not so. It seems like the final tree is only resolved after it gets all the way to the client and injected as props into a Relay.Container component.

Thoughts?

support for injection of relayContext in prepareData and shim to RelayEnvironment

Since I have been following the latest progress of react-relay, knowing that RelayContext is renamed to RelayEnvironment while adding injectNetworkLayer and injectTaskScheduler methods, it would be so nice if prepareData allows a relayContext to be passed down, with which I can put authorization into headers for each request on server-side.

btw, this module is so inspiring, thank you so much for you work!

Object.setPrototypeOf can be changed?

Hi @denvned and thank you for your work.
I was trying to make isomorphing rendering work on IE9 (sorry is not my fault).
For now the only issue I can see is the Object.setPrototypeOf in IsomorphicRootContainer.

There is another way to write it?
Thx!

Use it only for backend?

I got a question for people using this project: would it make sense to only use this for SSR? I got a nice setup already working on the client, so I was wondering if it would make sense to only use the server rendering capabilities of this library. Is it just not worth it and it's better to adapt my client code to also use isomorphic-relay, or it's doable and won't introduce performance pains and/or errors?

Thanks!

Allow patch releases for Relay peerDependency

The Relay peerDependency is currently fixed at 0.8.0. I get that minor releases usually require changes to this package, but can we get support for patch releases (~0.8.0)? It's kind of a pain having to --force install 0.8.1.

Document injected data format.

Hi,

I'd like to use just the client-side part of this. My app is built using Django, and I'd prefer not to add anything that requires javascript evaluation on the server. I can probably generate the json in Python. But in order to do that I'd like to know how the data is structured.

Should offer an isomorphic version of Relay.createContainer

Since now RelayEnvironment can be appointed, there grows the need for an relay able to commitUpdate or do sth else passed in props. I reviewed the source code of react-relay and isomorphic-relay, found that the relay passed down to LOC was not the original relayEnvironment in context, so I made sth like this

import React, { Component } from 'react';
import { createContainer, PropTypes as RelayPropTypes } from 'react-relay';

const getDisplayName = (WrappedComponent) => {
  return WrappedComponent.displayName || WrappedComponent.name || 'Component';
};

export default (spec) => (WrappedComponent) => {

  class ComponentWithRelayEnvironment extends Component {

    static displayName = `WithEnv(${getDisplayName(WrappedComponent)})`;

    static contextTypes = {
      relay: RelayPropTypes.Environment
    }

    render () {
      this.props.relay.__proto__ = this.context.relay;
      return <WrappedComponent {...this.props} />;
    }

  }

  return createContainer(ComponentWithRelayEnvironment, spec);
};

Hoping this feature could be merged in the next version, good day!

Help needed in applying isomorphic-relay

@denvned, thank you for your awesome work in the field of SSR in Relay ๐Ÿ‘

I tried to adapt your solution into my open-source project. My project consist of two repos:

Unfortunately, when I run the project and hit localhost:3000, a page is loading infinitely. I run the project in the following way:

  • npm install
  • npm run build
  • npm run start

... and I don't have any errors. I tried to debug the app, however, with no avail.

If you could check what is wrong and what might the root cause of infinite loading, I would be very grateful. I assume that it is my fault, however, it is quite hard to me to spot it.

complex type as argument in queries - fetchWithRetries(): Still no successful response after 1 retries, giving up.

First and foremost: thank you @denvned for all your hard work with the isomorphic-relay-* libraries. Reall(a)y amazing stuff! ๐Ÿ‘

I have a small issue now.. I'm trying to make some advanced graphql queries but as soon as I pass an object as argument, I get this error message:

Error: fetchWithRetries(): Still no successful response after 1 retries, giving up.
   at [..]/node_modules/fbjs/lib/fetchWithRetries.js:78:25
   at process._tickCallback (node.js:369:9)

Example:

countries(limit:3, where:{ active: true }){
   id,
}

I tried to pass it as a variable, also tried to escape it and pass it as "escaped string" but nothing helps..
When I'm sending the query directly via Graphiql it works well (so probably nothing wrong with my schema). As I know Relay also supports this type of conditions so I have a hunch something goes wrong in the isomorphic-relay networklayer..

Changelog

Hey @denvned! Thanks for everything you're doing with isomorphic-relay. I've been checking it out and it's awesome. Would it be possible for you to have a changelog with isomorphic-relay and isomorphic-relay-router? It would make following what needs to be changed a lot easier :)

Query running on both client and server.

I'm a little confused with what's going on here, but my GraphQL query is being run twice - once on server and once on the client; even though I'm following the example. The prepared data is being correctly serialized out to the rendered page and then deserialized for use with injectPreparedData, but the client still makes the query. My understanding is that because all the query data should be in the cache, the client doesn't need to run a query of its own.

Isomorphic JWT authentication

Hi @denvned, I'm focusing my project on this package which provide isomorphism to relay.
This is not a question related to the package "Which works great" but more related to the isomorphism world and authentication. I'm writing here because i believe you may suggest something very precious to me and community regarding this subject.

In my current project I want to achieve the following criteria with an isomorphic app:

  • Have my GraphQL end points accepting only JWT authentication and be stateless
  • Have my isomorphic app aware of user authentication when they refresh the page (with security in mind)

To solve this I needed 2 authentications, one for the isomorphic app "session based" and the second for the GraphQL server which is the wanted JWT.

As following I created a diagram that describe this authentication flow:
note: it start from the browser requesting authentication token to graphQL

iso authentication

The biggest downside of this approach "The reason why i'm posting here" is the way how I pass the token to Javascript / React. I'm actually rendering the token in a div Similar way how we preload the data with relay "It render the data as a JSON string in a HTML element"

On DOM loaded i extract the token information from the <div id="auth">{"token":"usertoken"}</div>
and pass it to a AuthStore.js which keep it in memory and pass it to Relay for sub-sequential request.

I implemented this approach and it works just fine, but i'm concerned about security of rendering the token in the div. If you have any better idea to pass this token to Javascript would be great. Or did you ever done a similar authentication with a Isomorphic app?

Thanks for the time to read this

IsomorphicRelay.injectNetworkLayer is not a function

This is looking good but I am getting hung up on something that is probably dead simple.

var IsomorphicRelay = require('isomorphic-relay');
var Relay = require('react-relay');

IsomorphicRelay.injectNetworkLayer(new Relay.DefaultNetworkLayer('http://127.0.0.1:8000/graphql'));

class RootRoute extends Relay.Route {
  static queries = {
    root: () => Relay.QL`query { root }`
  };

  static routeName = 'RootRoute';
}

module.exports = RootRoute;
Error: IsomorphicRelay.injectNetworkLayer is not a function

Possible incompatibility with Relay 0.6.1

After upgrading to Relay 0.6.1 there seems to be a problem at https://github.com/denvned/isomorphic-relay/blob/master/src/prepareData.js

RelayQuery.Node.prototype.getConcreteQueryNode = onCacheMiss => onCacheMiss();

The error looks like:

TypeError: onCacheMiss is not a function
   at RelayQueryField._RelayQuery2.default.Node.getConcreteQueryNode (<project root>/node_modules/isomorphic-relay/lib/prepareData.js:55:12)
   at Object.<anonymous> (<project root>/node_modules/react-relay/lib/toGraphQL.js:99:19)
   at Object.Field (<project root>/node_modules/react-relay/lib/toGraphQL.js:87:21)
   at toGraphQLSelection (<project root>/node_modules/react-relay/lib/toGraphQL.js:121:22)
   at Array.map (native)
   at Object.Query (<project root>/node_modules/react-relay/lib/toGraphQL.js:48:39)
   at _class.handleQueryPayload (<project root>/node_modules/isomorphic-relay/lib/prepareData.js:78:60)
   at <project root>/node_modules/react-relay/lib/RelayPendingQueryTracker.js:221:25
   at <project root>/node_modules/react-relay/lib/RelayTaskQueue.js:118:25
   at <project root>/node_modules/react-relay/lib/RelayTaskQueue.js:124:15

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.