Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I share context between a library component, and my application component?

I'm using lerna to create a monorepo where I'd have a structure like this:

root 
  packages
    application - Our root application 
    components  - Just some react components, that are to be used by the application

Here is a working Github with a simple example for this.

The issue I've run into, is I'm using Material-UI and its theming functionality, where at the application root we'll have a ThemeProvider:

import { ThemeProvider } from '@material-ui/styles';
//...

function App() {
  return (

  <ThemeProvider theme={theme}>
          <MyMaterialComponent/>
  </ThemeProvider>
  );
}

And later in the library component, we consume the theme, in our case using the makeStyles hook.

import React from 'react';
import { makeStyles } from '@material-ui/styles';
import Card from "@material-ui/core/Card";

const useStyles = makeStyles(theme => {
    console.log(theme); //When this component doesn't have access to the theme, this is `{}`
    return {
        root: {
            //color: theme.palette.primary.main  //will error
        }
    }
});

export function MyMaterialComponent({ }) {
    const classes = useStyles();
    return (<Card>
            <span className={classes.root}>This is some component</span>
        </Card>
    );

}

Now this seems all pretty straight forward. When we run this code all within the same package, it works fine. That styles function has access to the theme.

But when I'm running from another package (our application package), the the component library no longer has access to the theme (the theme is just an empty object).

The only way I currently know how to solve this, is the same way I've solved a similar hooks issue, which is to setup a webpack alias configuration in my application, to direct the component library to share the same same node module. (See this Github thread and the suggested solution).

ie. using react-app-rewired and customize-cra I have a config-overrides.js that looks like this:

const {
    override,
    addWebpackAlias,
  } = require("customize-cra");

const path = require('path'); 

module.exports = override( 
    addWebpackAlias({
        react: path.resolve('./node_modules/react'), 
        //comment out the line below to reproduce the issue
        "@material-ui/styles": path.resolve("./node_modules/@material-ui/styles") 
    })
)

or you could be managing your webpack manually to do a similar thing.

So this works fine, but this isn't a particularly satisfying solution.

Especially for a library like Material-UI, you want users to be able to use your component library without having them to mess with their webpack configuration.

So I figure I must be doing something wrong here - can you tell me what?

like image 619
dwjohnston Avatar asked May 28 '19 08:05

dwjohnston


1 Answers

You can achieve that by placing your @material-ui/core dependency from devDependencies to peerDependencies in your library's project. In my case, that solved my problem.

More information on peerDependencies :

https://classic.yarnpkg.com/en/docs/dependency-types/#toc-peerdependencies

like image 153
Mathis Delaunay Avatar answered Apr 27 '23 19:04

Mathis Delaunay