react
react copied to clipboard
Cannot read properties of undefined (reading 'createContext')
Hello we're seeing an issue when consuming our toolkit library in a new project.
I'll try to give a brief description of the project structure since it's quite big.
Our Component Toolkit Lib
This library contains lots of react components as well as Icons and is bundled and then consume via npm in the child application. The library is using styled-components
and uses a ThemeProvider
to wrap our application.
Since we're using many different Icons from phosphor
and want to "theme" them in a common way, we created a component called Icon
which accepts a recognised IconName
. We then use that name to map it to an Icon within @phosphor/react
Example of our icon-map.ts
file:
import { Armchair, Baby } from '@phosphor/react'
const iconMap: Record<IconName, Icon> = {
armchair: Armchair,
baby: Baby
}
export default iconMap
And then to consume these icons we look them up in the Icon.tsx
file:
// This is a simplified version but the pattern is correct
type IconProps = {
name: 'armchair' | 'baby'
color: string
}
const Icon: FC<IconProps> = ({ name, color }) => {
const Component = iconMap[name]
return <Component color={color} />
}
The problem then occurs when we use our library in the consuming applications.
export const start = () => {
ReactDOM.render(
<ThemeProvider theme='default'>
<div>This is our application</div>
</ThemeProvider>,
document.getElementById('root'),
)
}
And then we see the problem. Any ideas?
These are the main versions we're using in our application:
"dependencies": {
"@reduxjs/toolkit": "^1.9.5",
"react": "^18.0.2",
"react-dom": "^18.0.2",
"react-redux": "^8.1.2",
"@phosphor-icons/react": "^2.0.6"
},
"devDependencies": {
"@babel/cli": "^7.21.0",
"@babel/core": "^7.21.0",
"@babel/plugin-proposal-class-properties": "^7.0.0",
"@babel/plugin-proposal-decorators": "^7.8.3",
"@babel/plugin-syntax-dynamic-import": "^7.0.0",
"@babel/plugin-transform-runtime": "^7.21.0",
"@babel/preset-env": "^7.20.2",
"@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.21.0",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.10",
"@types/node": "^20.5.9",
"babel-loader": "8.1.0",
"babel-plugin-import": "^1.13.6",
"clean-webpack-plugin": "^4.0.0",
"copy-webpack-plugin": "^11.0.0",
"css-loader": "^6.7.3",
"dotenv-webpack": "^8.0.1",
"html-replace-webpack-plugin": "^2.6.0",
"html-webpack-plugin": "^5.5.0",
"mini-css-extract-plugin": "^2.7.2",
"process": "0.11.10",
"react-hot-loader": "^4.13.1",
"react-refresh": "^0.14.0",
"sass": "^1.66.1",
"sass-loader": "^13.2.0",
"tsconfig-paths-webpack-plugin": "^4.0.1",
"typescript": "^5.2.2",
"webpack": "^5.0.0",
"webpack-cli": "^4.3.0",
"webpack-dev-server": "^4.11.1",
"webpack-merge": "^5.8.0"
}
The error indicates that the UMD bundle is being imported. I don't know exactly why this would cause issue, but it could be related. It may have something to do with the React peer dependency and your bundling process, because I read this error as saying "Webpack can't find the React import at runtime", and with UMD react libraries, React
is expected to be available on the window object, IIRC.
Couple ideas:
You might want to try upgrading from 2.0.6 to 2.0.10, which has "type": "module"
by default.
Try changing from import React from 'react'
to import * as React from 'react'
in your component lib, and/or adding "esModuleInterop": true
and "allowSyntherocDefaultImports": true
to your tsconfig there too, if not already present.
This isn't an error I have seen with Phosphor before, and it looks more like something with your bundling.
Hey - Thanks for your suggestions @rektdeckard
Unfortunately still not joy. I bumped to 2.0.10
but that had no affect.
I have been poking around with our tsconfig
a bit but no avail. Perhaps if I drop it in here you could take a look and see if anything jumps out at you.
You suggestion to change the imports of react to import * as React...
- I've tried that in my ThemeProvider.web.tsx
file, but would you suggest doing this across the whole component library? There's about 100 components to make that change in, but I'd have thought doing in a single place would serve the purpose of the test.
{
"include": ["src", "@types/**/*", "contracts"],
"exclude": ["lib", "storybook/webpack.config.js", "./stories"],
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"baseUrl": ".",
"declaration": true,
"emitDeclarationOnly": false,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"module": "CommonJS",
"isolatedModules": true,
"jsx": "react",
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"moduleResolution": "node",
"outDir": "lib",
"noEmit": false,
"resolveJsonModule": true,
"rootDir": "./src",
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"target": "ES2015",
"paths": {
"contracts/*": ["contracts/*"]
}
},
}
Ok, so I've got it working... I'm cautious about calling it a total victory but it has unblocked me for what has been 3 days of not much fun.
I've added the minified React bundles to our html
file in script tags and then added React
to our webpack config as an externals
prop.
// public/index.html
<script crossorigin src="https://unpkg.com/[email protected]/umd/react.production.min.js"></script>
// webpack.common.js
externals: {
React: 'react',
},
In your response when you said that the umd couldn't find React
on the window, that pointed me down this route to look for a solution there, so thank you for that.
Just another thought, I see jsx: react
in your config. Have you tried switching to jsx: react-jsx
to use the automatic runtime? If not, React will need to be in scope in every file in your component library.
And in fact, in every consumer too