Подписаться на блог

UI library based on Chakra-UI bundling

Recently I tried to build some UI components library that based on Chakra-UI. At first my library didn’t contain react components and compiled using typescript and it worked perfectly. But after I added React components based on Chakra-UI and migrated build to webpack, I’ve got the next error from react hooks that were called inside Chakra-UI hooks such as useTheme:

Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.
By the way, Chakra-UI repository has this issue about this error - ((https://github.com/chakra-ui/chakra-ui/issues/495 #495)).

What is the reason for this error? useTheme hook and Chakra-UI library in whole use react library. As a result library imports react and react-dom. When webpack bundling your library that includes Chakra-UI, it includes react and react-dom to bundle of your library. In brief, you import react to your project, also you import your library with Chakra-UI that contains react too, as a result — you have at least two React copies. And in fact, it’s incorrect hook call.

How to fix it? Use only single react instance in your app. If you’re using webpack you can mark react and react-dom libraries as external libraries for your components library:

externals: {
  // mark "react" and react-dom as external packages that will import using commons
  react: 'commonjs react',
  'react-dom': 'commonjs react-dom'
},
output: {
  path: path.resolve('./'),
  libraryTarget: 'commonjs2', // set library target
  filename: '[name].js',
  library: '',
}

Now bundle of your library doesn’t contain react and react-dom. We marked libraries as external and have pure require calls but doesn’t have library in bundle:

/***/ "react":
/*!************************!*\
  !*** external "react" ***!
  \************************/
/*! no static exports found */
/***/ (function(module, exports) {
  module.exports = require("react");
/***/ }),

/***/ "react-dom":
/*!****************************!*\
  !*** external "react-dom" ***!
  \****************************/
/*! no static exports found */
/***/ (function(module, exports) {
  module.exports = require("react-dom");
/***/ })

This way also can help you if you’re using hooks and creating your own UI library without Chakra-UI.