【发布时间】:2021-04-08 23:33:23
【问题描述】:
我想在多个模块之间共享一个 api 实例,并能够使用外部配置对其进行初始化。我的代码使用 Webpack 和 Babel 将那些漂亮的 ES6 模块转换为浏览器可用的东西。我正在努力实现这一目标:
// api.js
let api = null;
export default api;
export function initApi(config) {
// use config to configure the shared api instance (e.g. with api base url)
api = ...
}
// ======================
// entry.js
import { initApi } from './api';
import App from './App';
// Initialize the single shared instance before anyone has the chance to use it
const apiConfig = ...
initApi(apiConfig);
// Create the app and run it
// ======================
// App.js
// RootComponent has an import dependency chain that eventually imports DeeplyNestedComponent.js
import RootComponent from './RootComponent';
// Actual App code not important
// ======================
// DeeplyNestedComponent.js
// PROBLEM! This "assignment" to the api var happens before initApi is run!
import api from '../../../../api';
api.getUser(123); // Fails because "api" stays null forever even after the initApi() call
出现“问题”是因为 ES6 模块是静态导入的,并且导入语句被提升。换句话说,简单地将import App from './App' 行移到initApi(apiConfig) 下方并不会在调用initApi 之后进行导入。
解决此问题的一种方法是从api.js(如果我有多个具有相同模式的此类共享对象,则在另一个globals.js文件中)导出一个对象,而不是像这样的单个变量:
// api.js
const api = {
api: null,
};
export default api;
export function initApi(config) {
// use config to configure the shared api instance (e.g. with api base url)
api.api = ... // <-- Notice the "api." notation
}
// ======================
// DeeplyNestedComponent.js
// api is now the object with an empty "api" property that will be created when initApi() is called
import api from '../../../../api';
api.api.getUser(123); // <-- Ugh :(
有没有办法在使用 ES6 模块时优雅地实现共享服务实例的初始化?
在我的情况下,DeeplyNestedComponent.js 必须仍然 import 以某种方式使用 api 实例。换句话说,不幸的是,没有任何上下文对象从App 一直传递到DeeplyNestedComponent.js,可以访问 api 实例。
【问题讨论】:
标签: javascript ecmascript-6 module