UNPKG

3.02 kBJavaScriptView Raw
1require('isomorphic-fetch');
2const React = require('react');
3const { existsSync, readFileSync } = require('fs');
4const {
5 Mixin,
6 strategies: {
7 sync: { override },
8 },
9} = require('hops-mixin');
10
11const { ApolloProvider, getDataFromTree } = require('react-apollo');
12const { default: ApolloClient } = require('apollo-client');
13const { HttpLink } = require('apollo-link-http');
14const {
15 InMemoryCache,
16 IntrospectionFragmentMatcher,
17 HeuristicFragmentMatcher,
18} = require('apollo-cache-inmemory');
19
20class GraphQLMixin extends Mixin {
21 introspectionResult = undefined;
22
23 constructor(config, element, { graphql: options = {} } = {}) {
24 super(config, element);
25
26 this.client = this.createClient(options);
27 }
28
29 createClient(options) {
30 return new ApolloClient(this.enhanceClientOptions(options));
31 }
32
33 enhanceClientOptions(options) {
34 return {
35 ...options,
36 link: options.link || this.getApolloLink(),
37 cache: options.cache || this.createCache(),
38 ssrMode: true,
39 };
40 }
41
42 getApolloLink() {
43 return new HttpLink({
44 uri: this.config.graphqlUri,
45 });
46 }
47
48 createCache() {
49 return new InMemoryCache({ fragmentMatcher: this.createFragmentMatcher() });
50 }
51
52 createFragmentMatcher() {
53 if (this.introspectionResult === undefined) {
54 try {
55 if (existsSync(this.config.fragmentsFile)) {
56 this.introspectionResult = JSON.parse(
57 readFileSync(this.config.fragmentsFile, 'utf-8')
58 );
59 }
60 } catch (_) {
61 this.introspectionResult = null;
62 console.warn(
63 'Could not find a graphql introspection query result at %s.',
64 this.config.fragmentsFile,
65 'You might need to execute `hops graphql introspect`'
66 );
67 }
68 } else {
69 return new IntrospectionFragmentMatcher({
70 introspectionQueryResultData: this.introspectionResult,
71 });
72 }
73 return new HeuristicFragmentMatcher();
74 }
75
76 fetchData(data = {}, element) {
77 return this.prefetchData(element).then(() => {
78 return {
79 ...data,
80 globals: {
81 ...(data.globals || {}),
82 APOLLO_IRQD: this.introspectionResult,
83 APOLLO_STATE: this.client.cache.extract(),
84 },
85 };
86 });
87 }
88
89 prefetchData(element) {
90 return this.shouldPrefetchOnServer()
91 ? getDataFromTree(element)
92 : Promise.resolve();
93 }
94
95 shouldPrefetchOnServer() {
96 const { shouldPrefetchOnServer } = this.config;
97 return typeof shouldPrefetchOnServer === 'boolean'
98 ? shouldPrefetchOnServer
99 : true;
100 }
101
102 getTemplateData(data) {
103 return {
104 ...data,
105 globals: {
106 ...data.globals,
107 ...(data.fetchedData || {}).globals,
108 },
109 };
110 }
111
112 enhanceElement(reactElement) {
113 return React.createElement(
114 ApolloProvider,
115 { client: this.client },
116 reactElement
117 );
118 }
119}
120
121GraphQLMixin.strategies = {
122 getApolloLink: override,
123 shouldPrefetchOnServer: override,
124};
125
126module.exports = GraphQLMixin;