Add API for adding fragment matchers to apollo client; delay apollo client initialization until after app initialization

This commit is contained in:
SachaG 2017-09-14 10:06:41 +02:00
parent ff678b9fab
commit 1ee92ea9cc
7 changed files with 106 additions and 48 deletions

View file

@ -4,8 +4,6 @@ import { Meteor } from 'meteor/meteor';
import { getRenderContext } from './render_context.js';
const context = getRenderContext();
function setToken(loginToken, expires) {
if (loginToken && expires !== -1) {
cookie.save('meteor_login_token', loginToken, {
@ -20,6 +18,7 @@ function setToken(loginToken, expires) {
}
function resetToken() {
const context = getRenderContext();
const loginToken = global.localStorage['Meteor.loginToken'];
const loginTokenExpires = new Date(global.localStorage['Meteor.loginTokenExpires']);

View file

@ -5,43 +5,57 @@ import {
createApolloClient,
configureStore,
addAction, getActions, addReducer, getReducers, addMiddleware, getMiddlewares,
Utils,
} from '../modules/index.js';
// init
const history = browserHistory;
const loginToken = global.localStorage['Meteor.loginToken'];
const apolloClient = createApolloClient();
addReducer({ apollo: apolloClient.reducer() });
addMiddleware(apolloClient.middleware());
let context;
// init context
const context = {
history,
loginToken,
apolloClient,
addAction, // context.addAction same as addAction
getActions, // context.getActions same as getActions
addReducer, // context.addReducer same as addReducer
getReducers, // context.getReducers same as getReducers
addMiddleware, // context.addMiddleware same as addMiddleware
getMiddlewares, // context.getMiddlewares same as getMiddlewares
};
export const initContext = () => {
// init store
context.store = configureStore(context.getReducers, {}, (store) => {
let chain, newDispatch;
return next => (action) => {
if (!chain) {
chain = context.getMiddlewares().map(middleware => middleware(store));
newDispatch = compose(...chain)(next)
}
return newDispatch(action);
// init
const history = browserHistory;
const loginToken = global.localStorage['Meteor.loginToken'];
const apolloClient = createApolloClient();
addReducer({ apollo: apolloClient.reducer() });
addMiddleware(apolloClient.middleware());
// init context
context = {
history,
loginToken,
apolloClient,
addAction, // context.addAction same as addAction
getActions, // context.getActions same as getActions
addReducer, // context.addReducer same as addReducer
getReducers, // context.getReducers same as getReducers
addMiddleware, // context.addMiddleware same as addMiddleware
getMiddlewares, // context.getMiddlewares same as getMiddlewares
};
})
// init store
context.store = configureStore(context.getReducers, {}, (store) => {
let chain, newDispatch;
return next => (action) => {
if (!chain) {
chain = context.getMiddlewares().map(middleware => middleware(store));
newDispatch = compose(...chain)(next)
}
return newDispatch(action);
};
})
}
// render context object
export const renderContext = { get: () => context };
export const renderContext = {
get: () => {
if (typeof context === 'undefined') {
initContext();
}
return context
}
};
// render context get function
export const getRenderContext = () => renderContext.get();

View file

@ -4,6 +4,8 @@ import 'isomorphic-fetch';
import { Meteor } from 'meteor/meteor';
import { getSetting } from './settings.js';
import { getFragmentMatcher } from './fragment_matcher.js';
import { Callbacks, runCallbacks } from './callbacks.js';
const defaultNetworkInterfaceConfig = {
path: '/graphql', // default graphql server endpoint
@ -74,20 +76,30 @@ const createMeteorNetworkInterface = (givenConfig = {}) => {
return networkInterface;
};
const meteorClientConfig = networkInterfaceConfig => ({
ssrMode: Meteor.isServer,
networkInterface: createMeteorNetworkInterface(networkInterfaceConfig),
queryDeduplication: true, // http://dev.apollodata.com/core/network.html#query-deduplication
addTypename: true,
// Default to using Mongo _id, must use _id for queries.
dataIdFromObject(result) {
if (result._id && result.__typename) {
const dataId = result.__typename + result._id;
return dataId;
}
return null;
},
});
const meteorClientConfig = networkInterfaceConfig => {
export const createApolloClient = options => new ApolloClient(meteorClientConfig(options));
return {
ssrMode: Meteor.isServer,
networkInterface: createMeteorNetworkInterface(networkInterfaceConfig),
queryDeduplication: true, // http://dev.apollodata.com/core/network.html#query-deduplication
addTypename: true,
fragmentMatcher: getFragmentMatcher(),
// Default to using Mongo _id, must use _id for queries.
dataIdFromObject(result) {
if (result._id && result.__typename) {
const dataId = result.__typename + result._id;
return dataId;
}
return null;
},
}
};
export const createApolloClient = options => {
runCallbacks('apolloclient.init.before');
return new ApolloClient(meteorClientConfig(options));
};

View file

@ -0,0 +1,18 @@
import { IntrospectionFragmentMatcher } from 'react-apollo';
export const FragmentMatcher = [];
export const addToFragmentMatcher = fragmentMatcher => {
FragmentMatcher.push(fragmentMatcher);
}
export const getFragmentMatcher = () => {
const fm = {
introspectionQueryResultData: {
__schema: {
types: FragmentMatcher,
},
}
};
return new IntrospectionFragmentMatcher(fm);
}

View file

@ -23,4 +23,5 @@ export * from './fragments.js';
export * from './apollo.js';
export * from './dynamic_loader.js';
export * from './admin.js';
export * from './fragment_matcher.js';
// export * from './resolvers.js';

View file

@ -0,0 +1,12 @@
import { VoteableCollections } from '../modules/make_voteable.js';
import { addToFragmentMatcher, addCallback } from 'meteor/vulcan:core';
function AddVoteableFragmentMatcher() {
addToFragmentMatcher({
kind: 'UNION',
name: 'Voteable',
possibleTypes: VoteableCollections.map(collection => ({name: collection.options.collectionName}))
});
return {};
}
addCallback('apolloclient.init.before', AddVoteableFragmentMatcher);

View file

@ -1 +1,3 @@
import './fragment_matcher.js';
export * from '../modules/index.js';