export default()

in fusion-plugin-apollo/src/plugin.js [66:185]


export default (renderFn: Render) =>
  createPlugin<DepsType, ProvidesType>({
    deps: getDeps(),
    provides(deps) {
      if (__BROWSER__) {
        return renderFn;
      }
      return (el, ctx) => {
        return serverRender(el, deps.logger, deps.getDataFromTree).then(() => {
          return renderFn(el, ctx);
        });
      };
    },
    middleware({
      RouteTags,
      logger,
      schema,
      endpoint = '/graphql',
      getApolloClient,
      apolloContext = ctx => {
        return ctx;
      },
      bodyParserConfig = {},
      defaultOptionsConfig = {},
    }) {
      const renderMiddleware = async (ctx, next) => {
        if (!ctx.element) {
          return next();
        }
        let initialState = null;
        if (__BROWSER__) {
          // Deserialize initial state for the browser
          const apolloState = document.getElementById('__APOLLO_STATE__');
          if (apolloState) {
            initialState = JSON.parse(unescape(apolloState.textContent));
          }
        }
        // Create the client and apollo provider
        const client = getApolloClient(ctx, initialState);
        ctx.element = (
          <ApolloCacheContext.Provider value={client.cache}>
            <ApolloProvider client={client}>{ctx.element}</ApolloProvider>
          </ApolloCacheContext.Provider>
        );

        await next();

        if (__NODE__) {
          // Serialize state into html on server side render
          const initialState = client.cache && client.cache.extract();
          const serialized = JSON.stringify(initialState);
          // eslint-disable-next-line prettier/prettier
          const script = html`
            <script type="application/json" id="__APOLLO_STATE__">
              ${String(serialized)}
            </script>
          `;
          ctx.template.body.push(script);
        }
      };
      if (__NODE__ && schema) {
        const getApolloContext = ctx => {
          if (typeof apolloContext === 'function') {
            return apolloContext(ctx);
          }
          return apolloContext;
        };
        const server = new ApolloServer({
          formatError: error => {
            logger && logger.error(error.message, error);
            return error;
          },
          ...defaultOptionsConfig,
          schema,
          // investigate other options
          context: ({ctx}) => {
            return ctx;
          },
          executor: async requestContext => {
            const fusionCtx = requestContext.context;
            const routeTags = RouteTags.from(fusionCtx);
            routeTags.name = 'graphql';
            const apolloCtx = getApolloContext(fusionCtx);
            const client = getApolloClient(fusionCtx, {});
            // $FlowFixMe
            const queryObservable = client.queryManager.getObservableFromLink(
              requestContext.document,
              apolloCtx,
              requestContext.request.variables
            );
            return new Promise((resolve, reject) => {
              queryObservable.subscribe({
                next(x) {
                  resolve(x);
                },
                error(err) {
                  reject(err);
                },
              });
            });
          },
        });
        let serverMiddleware = [];
        server.applyMiddleware({
          // switch to server.getMiddleware once https://github.com/apollographql/apollo-server/pull/2435 lands
          app: {
            use: m => {
              serverMiddleware.push(m);
            },
          },
          // investigate other options
          path: endpoint,
          bodyParserConfig,
        });
        return compose([...serverMiddleware, renderMiddleware]);
      } else {
        return renderMiddleware;
      }
    },
  });