记录一下最近写个人页遇到的一个问题。
0x00 问题背景
假设有这样一个组件库my-compnents
和这样一个页面工程my-project
,它们同时依赖some-dep
。some-dep
导出了一个ContextTheme
用于给整个页面提供主题。my-components
导出了一个内部使用Theme
的组件Component
。my-project
中的一个页面结构如下:
import { MyComponent } from 'my-components';
import { Theme, createTheme } from 'some-dep'
function index() {
const myTheme = createTheme();
return (
<Theme.Provider theme={myTheme}>
{ /* 来自my-components的组件MyComponent内部导入了来自some-dep的Theme.Consumer */ }
<MyComponent />
<Theme.Provider>
)
}
看起来似乎没有什么问题。但是,在MyComponent
内部取Context的话,只会得到undefined
。
0x01 问题成因
很容易就能想到,问题可能出在打包这个过程中。在这个例子中,我们在my-project
和my-components
中分别地导入了some-dep
。相互独立的导入过程产生了两个相互独立的Context。
我们在my-project
中使用createTheme
实例化了Context对象并传给my-project
中的Provider,但这一切与my-components
无关。my-components
有独立的Context,但是这个Context始终没有被createTheme
实例化(毕竟,设计本意只是想让组件去拿整个上下文中的Context对象),MyComponent
中的Consumer也就只能获取到undefined
了。
0x02 解决方案
我们需要让两个包使用同一个Context,准确来说,是my-project
定义的那个。具体的方法是,在使用Consumer的地方(也就是my-component
)将提供Provider的包(也就是some-dep
)定义为external
。
// webpack
{
...
externals: {
...
'some-dep': 'some-dep'
},
...
}
// rollup
{
...
external: ['some-dep'],
...
}
这样,问题就解决了。
参考链接: