依赖注入的本质是组件声明所需依赖,由外部容器统一创建并提供稳定引用,核心在于传递契约(创建权、唯一性、生命周期),而非简单赋值;需避免内部硬编码构造,改用工厂函数在启动时一次性生成服务对象,再通过 provide/inject(Vue)、Context/Hook(React)或 Plasmo 的环境与运行时机制安全注入。

变量的依赖注入不是把值“塞进去”,而是让组件声明它需要什么,再由外部统一提供稳定、可控的引用。关键不在传数据,而在传契约——谁负责创建、谁保证唯一、谁控制生命周期。
明确变量来源与生命周期
避免在组件内部用 const config = { apiUrl: "..." } 或 new ApiClient() 直接构造变量。这类写法会让变量脱离统一管理,导致多实例、状态不一致、无法替换(比如切 mock 环境时要全项目 grep)。正确做法是:把变量封装进工厂函数,在应用启动或根组件中一次性创建,并作为“服务对象”的一部分注入。
- 定义一个 createAppServices(env) 函数,返回含配置、API 实例、工具类等的对象
- 确保该函数只执行一次,返回的对象在整个应用生命周期内保持同一引用
- 变量如 baseUrl、token、logger 都应随服务对象整体注入,而非单独拎出
Vue 中用 provide/inject 安全传递
Vue 的 provide/inject 是响应式通道,不是 DI 容器。不能每次 setup 都 provide("api", new ApiClient()),否则子组件拿到的是新实例,单例失效。必须先创建好稳定对象,再整包注入。
- 在根组件 setup 中调用 provide("services", createAppServices(env))
- 子组件用 inject("services") 获取整个服务对象,再解构使用:const { api, config } = inject("services")
- 若需类型安全,配合 InjectionKey 显式声明,避免字符串 key 导致 TS 推导失败和 IDE 补全丢失
React 中用 Context + 工厂函数模拟
React 没有原生 provide,但可用 useContext 搭配不可变的服务对象实现同等效果。重点在于 Context value 必须稳定——不能在渲染中反复新建对象。
- 创建 ServicesContext,并在顶层
中传入 - 自定义 Hook 如 useServices() 内部调用 useContext(ServicesContext),直接返回解构后的服务
- 所有消费组件都通过该 Hook 获取,确保引用一致、可测试、可替换
Plasmo 扩展中的环境与运行时注入
Plasmo 提供两层注入能力:构建期注入环境变量,运行期注入服务实例。这对扩展特别实用——比如背景页和服务工作器需要共享 API 配置,又需在内容脚本中复用同一 logger 实例。
- 用 @plasmo/utils/env 的 injectEnv("PLASMO_PUBLIC_API_URL") 在编译时注入静态配置
- 在 background service worker 中,通过 injectHmrSocket 或自定义 runtime 注入可热更新的服务(如消息总线、状态同步器)
- 跨上下文(popup/content/background)共享变量时,优先走 chrome.storage 或 message passing,而非直接注入——因各上下文隔离,引用不互通

















