记录一下最近写个人页遇到的一个问题。
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'],
...
}这样,问题就解决了。
参考链接: