Chrome扩展@apollo/client迁移无法传customFetch调用background.js接口
问题背景
Chrome扩展项目中原先使用apollo-boost导入ApolloClient,通过传入fetch: customFetch参数实现从background.js发起GraphQL API调用。由于apollo-boost已经废弃,迁移到新版Apollo Client过程中遇到异常:
- 从
@apollo/client导入ApolloClient时,找不到传入customFetch函数的配置入口;官方文档仅说明了RESTLink场景下customFetch的配置方式,没有提及GraphQL请求场景的对应配置方法。 - 按照Apollo官方迁移文档从
apollo-client包导入ApolloClient时,配置不生效,甚至完全没有发起API请求。 - 旧版使用
apollo-boost时还会触发Invariant Violation: 29 on react apollo grapql报错,无法定位配置错误点。
迁移后(存在问题的)代码
import { configureStore } from '@koncert/shared-components'; import React from 'react'; import { Provider } from 'react-redux'; import { MemoryRouter as Router } from 'react-router-dom'; import Routes from '../../components/Routes'; // import ApolloClient from 'apollo-client'; import '../../styles/app.scss'; import customFetch from '../../lib/fetch-mp'; // import { InMemoryCache } from 'apollo-cache-inmemory'; import '../../Vendor'; import { TokenProvider } from '../../components/TokenContext'; import ErrorBoundary from '../../components/Common/ErrorBoundary.tsx'; import { ApolloClient, ApolloProvider } from 'apollo-client'; import { InMemoryCache } from 'apollo-cache-inmemory'; import { HttpLink } from 'apollo-link-http'; import { onError } from 'apollo-link-error'; import { ApolloLink } from 'apollo-link'; const client = new ApolloClient({ link: ApolloLink.from([ onError(({ graphQLErrors, networkError }) => { if (graphQLErrors) graphQLErrors.forEach(({ message, locations, path }) => console.log( `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`, ), ); if (networkError) console.log(`[Network error]: ${networkError}`); }), new HttpLink({ uri: `${process.env.REACT_APP_STORIES_GRAPHQL_URI}`, fetch: customFetch, credentials: 'same-origin' }) ]), cache: new InMemoryCache(), });
迁移前(apollo-boost版本可运行但有报错)代码
import { ApolloProvider } from '@apollo/react-hooks'; import { configureStore } from '@koncert/shared-components'; import React from 'react'; import { Provider } from 'react-redux'; import { MemoryRouter as Router } from 'react-router-dom'; import Routes from '../../components/Routes'; import ApolloClient from 'apollo-boost'; import '../../styles/app.scss'; import customFetch from '../../lib/fetch-mp'; import { InMemoryCache } from 'apollo-cache-inmemory'; import '../../Vendor'; import { TokenProvider } from '../../components/TokenContext'; import ErrorBoundary from '../../components/Common/ErrorBoundary.tsx'; const client = new ApolloClient({ uri: `${process.env.REACT_APP_STORIES_GRAPHQL_URI}`, fetch: customFetch, cache: new InMemoryCache(), });
问题原因与修复方案
你现在的代码有两个核心问题,直接导致请求发不出去、配置不生效:
- 导入路径错误:从
apollo-client包同时导入ApolloClient和ApolloProvider是完全错误的。apollo-client只包含核心客户端逻辑,ApolloProvider属于React绑定层的导出,旧拆分版本里这个API在@apollo/react-hooks包下,跨包导入不存在的导出会直接导致客户端实例初始化异常,根本走不到发请求的逻辑。 - 对新版Apollo Client的配置存在误解:GraphQL场景下自定义fetch完全不需要依赖RESTLink,给
HttpLink传入fetch参数即可生效。最新版@apollo/client(v3+)已经把HttpLink、InMemoryCache、错误处理链路、React绑定等所有依赖全部内置,不需要单独安装零散的apollo-link、apollo-cache类包。
具体修复步骤
- 先清理冗余依赖:把项目里的
apollo-boost、apollo-client、apollo-link-http、apollo-link-error、apollo-cache-inmemory、@apollo/react-hooks这些零散的Apollo相关包全部卸载,只保留最新版@apollo/client即可,从根源避免多包版本冲突。 - 替换导入和客户端初始化逻辑,代码如下:
// 所有Apollo相关API统一从@apollo/client导入,不需要拆分引入 import { ApolloClient, ApolloProvider, InMemoryCache, HttpLink, ApolloLink, onError } from '@apollo/client'; import customFetch from '../../lib/fetch-mp'; const client = new ApolloClient({ link: ApolloLink.from([ onError(({ graphQLErrors, networkError }) => { if (graphQLErrors) { graphQLErrors.forEach(({ message, locations, path }) => console.log(`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`) ); } if (networkError) console.log(`[Network error]: ${networkError}`); }), new HttpLink({ uri: process.env.REACT_APP_STORIES_GRAPHQL_URI, fetch: customFetch, // 此处直接传入自定义fetch,和apollo-boost时期的传参逻辑完全一致 credentials: 'same-origin' }) ]), cache: new InMemoryCache(), ssrMode: false, // Chrome扩展环境下关闭SSR检测,避免初始化异常 connectToDevTools: process.env.NODE_ENV === 'development' });
- 之前遇到的Invariant Violation: 29 on react apollo grapql报错,本质是组件树无法获取到正确的Apollo上下文导致的——基本都是多版本Apollo包冲突、
ApolloProvider导入来源错误引发的,把依赖统一收敛到@apollo/client之后这个问题会直接解决。
补充提醒:Chrome扩展的内容脚本存在上下文隔离,如果你的customFetch是要走background.js发起请求,确保customFetch内部的runtime通信逻辑没有被隔离策略拦截,请求头、cookie配置符合扩展的权限声明要求。
内容的提问来源于stack exchange,提问作者Dilip A
相关产品推荐
相关产品推荐

