af / apollo-local-query Goto Github PK
View Code? Open in Web Editor NEWSimpler server rendering with apollo-client 1.x, using a local GraphQL networkInterface
License: MIT License
Simpler server rendering with apollo-client 1.x, using a local GraphQL networkInterface
License: MIT License
Great library! However, an apollo client has the option of giving an dataIdFromObject
option which is for caching in the browser. But this library has no such option, so when rehydrating the store everything gets the wrong ID's in the store. Is there a simple fix I am overlooking?
Currently, we need to pass graphql
library to createLocalInterface
, why do we need this?
Apollo is using it by default, is it possible to use it by default too so we have to provide only the schema or what is the use-case for this?
The ApolloClient
object in the new 2.0 version requires that both link
and cache
be passed in. How is this library supposed to be used in 2.0?
Hi, Apollo-local-query looks to be a great package for me to avoid go out and back through the networking stack, before I'm looking to gain some speed to render the data of my queries.
Unfortunately, I'm facing some troubles to install it in my context:
After doing the installation as presented in the readme, I'm getting the following error, which says that the dependencies related to the Koa server:
ERROR Failed to compile with 18 errors
These modules were not found:
* child_process in ./node_modules/stripe/lib/stripe.js, ./node_modules/os-locale/index.js
* net in ./node_modules/forever-agent/index.js, ./node_modules/tunnel-agent/index.js and 2 others
* tls in ./node_modules/forever-agent/index.js, ./node_modules/tunnel-agent/index.js and 1 other
* module in ./node_modules/require_optional/node_modules/resolve-from/index.js
* fs in ./node_modules/nconf/lib/nconf.js, ./node_modules/y18n/index.js and 6 others
To install them, you can run: npm install --save child_process net tls module fs
My working code before the installation was looking like this:
import { ApolloClient, createNetworkInterface } from 'react-apollo';
import fetch from 'isomorphic-fetch';
let apolloClient = null;
// Polyfill fetch() on the server (used by apollo-client)
if (!process.browser) {
global.fetch = fetch;
}
function create() {
return new ApolloClient({
ssrMode: !process.browser, // Disables forceFetch on the server (so queries are only run once)
networkInterface: createNetworkInterface({
uri: '/graphql',
opts: {
credentials: 'include'
}
})
});
}
export default function initApollo() {
// Make sure to create a new client for every server-side request so that data
// isn't shared between connections (which would be bad)
if (!process.browser) {
return create();
}
// Reuse client on the client-side
if (!apolloClient) {
apolloClient = create();
}
return apolloClient;
}
After the installation of apollo-local-query, it was looking like this:
import { ApolloClient, createNetworkInterface } from 'react-apollo';
// >>I've tried with it too import fetch from 'isomorphic-fetch';
import { createLocalInterface } from 'apollo-local-query';
import * as graphql from 'graphql'; >> // I've also tried with: import graphql from 'graphql';
import schema from '../../server/graphql/schema';
const isServer = !process.browser;
const options = { credentials: 'include' };
if (isServer) {
options.networkInterface = createLocalInterface(graphql, schema);
options.ssrMode = true;
}
const myClient = new ApolloClient(options)
export default function initApollo() {
return myClient;
}
For information, my schema.js is looking like this:
const { makeExecutableSchema } = require('graphql-tools');
const resolvers = require('./resolvers');
const Schemas = require('./schemas');
const { User, Service } = require('./types');
const Queries = `
type Query {
${User.queries}
${Service.queries}
}
`;
const Mutations = `
type Mutation {
${User.mutations}
${Service.mutations}
}
`;
const Scalars = `
scalar Date
`;
const Inputs = `
input TranslationInput {
en: String
es: String
ca: String
fr: String
}
// ... With others inputs
`;
module.exports = makeExecutableSchema({
typeDefs: [Queries, Mutations, Scalars, Inputs, ...Schemas],
resolvers
});
The file where I call the "initApollo" function to pass the ApolloClient to the Apollo Provider is looking like this:
import React from 'react'
import PropTypes from 'prop-types'
import { ApolloProvider, getDataFromTree } from 'react-apollo'
import Head from 'next/head'
import initApollo from './apollo'
import initRedux from './store'
// Gets the display name of a JSX component for dev tools
function getComponentDisplayName (Component) {
return Component.displayName || Component.name || 'Unknown'
}
export default ComposedComponent => {
return class WithData extends React.Component {
static displayName = `WithData(${getComponentDisplayName(ComposedComponent)})`
static propTypes = {
serverState: PropTypes.object.isRequired
}
static async getInitialProps (ctx) {
let serverState = {}
// Evaluate the composed component's getInitialProps()
let composedInitialProps = {}
if (ComposedComponent.getInitialProps) {
composedInitialProps = await ComposedComponent.getInitialProps(ctx)
}
// Run all GraphQL queries in the component tree
// and extract the resulting data
if (!process.browser) {
const apollo = initApollo()
const redux = initRedux(apollo, { test: { also: 'this' } })
// Provide the `url` prop data in case a GraphQL query uses it
const url = {query: ctx.query, pathname: ctx.pathname}
try {
// Run all GraphQL queries
await getDataFromTree(
// No need to use the Redux Provider
// because Apollo sets up the store for us
<ApolloProvider client={apollo} store={redux}>
<ComposedComponent url={url} {...composedInitialProps} />
</ApolloProvider>
)
} catch (error) {
// Prevent Apollo Client GraphQL errors from crashing SSR.
// Handle them in components via the data.error prop:
// http://dev.apollodata.com/react/api-queries.html#graphql-query-data-error
}
// getDataFromTree does not call componentWillUnmount
// head side effect therefore need to be cleared manually
Head.rewind()
// Extract query data from the store
const state = redux.getState()
// No need to include other initial Redux state because when it
// initialises on the client-side it'll create it again anyway
serverState = {
apollo: { // Only include the Apollo data state
data: state.apollo.data
}
}
}
return {
serverState,
...composedInitialProps
}
}
constructor (props) {
super(props)
this.apollo = initApollo()
this.redux = initRedux(this.apollo, this.props.serverState)
}
render () {
return (
// No need to use the Redux Provider
// because Apollo sets up the store for us
<ApolloProvider client={this.apollo} store={this.redux}>
<ComposedComponent {...this.props} />
</ApolloProvider>
)
}
}
}
And my server.js with Koa is looking like this:
const IntlPolyfill = require('intl');
const Koa = require('koa');
const convert = require('koa-convert');
const router = require('./routes.js');
const session = require('koa-generic-session');
const passport = require('koa-passport');
const bodyParser = require('koa-bodyparser');
const accepts = require('accepts');
const next = require('next');
const { graphqlKoa, graphiqlKoa } = require('graphql-server-koa');
const { basename } = require('path');
const glob = require('glob');
const { readFileSync } = require('fs');
const en = require('../helpers/intl/messages/en.js');
const es = require('../helpers/intl/messages/en.js');
const ca = require('../helpers/intl/messages/en.js');
const fr = require('../helpers/intl/messages/en.js');
const messages = { en, es, ca, fr };
// const compression = require('compression');
require('./auth');
const { Company } = require('./models');
const schema = require('./graphql/schema');
const nconf = require('../env/nconf');
Intl.NumberFormat = IntlPolyfill.NumberFormat;
Intl.DateTimeFormat = IntlPolyfill.DateTimeFormat;
const port = process.env.PORT || nconf.get('PORT');
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
const languages = glob.sync('./helpers/intl/messages/*.js').map(f => basename(f, '.js'));
const localeDataCache = new Map();
const getLocaleDataScript = (locale) => {
// const lang = locale.split('-')[0]
const lang = locale;
if (!localeDataCache.has(lang)) {
const localeDataFile = require.resolve(`react-intl/locale-data/${lang}`);
const localeDataScript = readFileSync(localeDataFile, 'utf8');
localeDataCache.set(lang, localeDataScript);
}
return localeDataCache.get(lang);
};
const getMessages = (locale, companyMessages) =>
Object.assign({}, messages[locale], companyMessages);
app.keys = [nconf.get('APP_KEYS')];
app.prepare()
.then(() => {
const server = new Koa();
server
.use(bodyParser())
.use(convert(session()))
.use(passport.initialize())
.use(passport.session())
.use(router.routes())
.use(router.allowedMethods());
// .use(compression())
router.post('/graphql', graphqlKoa(async (ctx) => {
const host = ctx.req.headers.host;
const company = await Company.findOne({ website_url: host.replace('www.', '') });
return ({
schema,
context: {
ctx,
user: ctx.state.user,
company
}
});
}));
router.get('/graphiql', graphiqlKoa({ endpointURL: '/graphql' }));
router.get('*', async (ctx) => {
const host = ctx.req.headers.host;
const accept = accepts(ctx.req);
const locale = accept.language(languages);
const company = await Company.findOne({ website_url: host.replace('www.', '') });
ctx.req.company = company;
ctx.req.locale = locale;
ctx.req.localeDataScript = getLocaleDataScript(locale);
ctx.req.messages = getMessages(locale, company.website[locale]);
await handle(ctx.req, ctx.res);
ctx.respond = false;
});
server.listen(port, (err) => {
if (err) throw err;
console.log(`> Ready on http://localhost:${port}`);
});
});
Does anyone have an idea how to fix this issue?
If someone succeed to give me some hint about how to fix it, I'm proposing myself to produce some extra documentation for apollo-local-query to illustrate the setup for this context! ;)
Thank for your help!
I am getting the following error, am I missing something?
Error: only absolute urls are supported
at /app_root/node_modules/node-fetch/index.js:54:10
W20161217-12:43:23.389(1)? (STDERR) const createLocalInterface = (graphql, schema, {rootValue = null, context = null} = {}) => {
W20161217-12:43:23.390(1)? (STDERR) ^
W20161217-12:43:23.390(1)? (STDERR)
W20161217-12:43:23.390(1)? (STDERR) ReferenceError: Invalid left-hand side in assignment
just wanted to let you know
I'm trying to use this in the context of react-starter-kit. After integrating apollo-client according to its docs I proceeded to incorporate this similarly straightforwardly. However, for me this causes server-side rendering to lock up (browser times out) without throwing any errors, so I'm somewhat clueless as to the cause (and how to go about debugging it). Any ideas?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.