Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I bundle MUI theme with rollup

I've been working on pulling our existing react FE components out of our main repo, and into a separate repo that I am bundling with rollup. Our old code was using makeStyles and I have been switching that over to styled-components but still keeping the previous MUI theme. I've setup storybook and am wrapping that in styled components theme provider, in order to access the theme inside the styled components.

The structure looks like

components
  \src
    index.ts(imports and exports components)
    \theme(MUI theme)
    \components
      \buttons
        button.tsx(react button code)
        index.ts(imports and exports button)
  \lib(rollup spits this out)

Finally, to the question. After I bundle everything with rollup, I do an NPM install, and import it into a different project. The problem is, I'm not getting the proper theming in the imported components. Here is a somewhat simplified version of my button.

import React from "react";
import { Button as MaterialButton, ButtonProps } from "@material-ui/core";
import styled from "styled-components";

export interface MyButtonProps extends ButtonProps {
  error?: boolean;
  target?: string;
}

const StyledButton = styled(MaterialButton)`
  &.error {
    background: ${(props) => props.theme.palette.error.main};
    color: #fff;
    &:hover {
      background: ${(props) => props.theme.palette.error.main};
    }
  }
`;

const Button = ({
  error,
  className,
  ...rest}: MyButtonProps) => {
  className += error ? " error" : "";
  return (
    <StyledButton
      {...rest}
      className={className}
    >
      {children}
    </StyledButton>
  );
};

export default Button;

So, if I put error attribute on the button, I do get the correct color from my theme. However, if I put color="primary" I do not get the correct color. I also don't have any of my base styles from the theme.

I haven't been able to figure out how to get this theme into the components I'm bundling with rollup. Finally, here is my rollup config.

import peerDepsExternal from "rollup-plugin-peer-deps-external";
import resolve from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import typescript from "rollup-plugin-typescript2";
import postcss from "rollup-plugin-postcss";
import svg from "rollup-plugin-svg-import";

const packageJson = require("./package.json");

export default {
  input: "src/index.ts",
  output: [
    {
      file: packageJson.main,
      format: "cjs",
      sourcemap: true,
    },
    {
      file: packageJson.module,
      format: "esm",
      sourcemap: true,
    },
  ],
  plugins: [
    peerDepsExternal(),
    resolve(),
    commonjs(),
    svg(),
    typescript({ useTsconfigDeclarationDir: true }),
    postcss({
      extensions: [".css"],
    }),
  ],
};

like image 767
Joe Madden Avatar asked Sep 05 '25 03:09

Joe Madden


1 Answers

For anyone who has stumbled upon this and is curious about the answer. Here is what I ended up doing. Hopefully this is the correct solution. One thing that is a bummer, I end up with MUI ThemeProvider giving me it's generated class names. This means in my styled components, I'll occasionally need to do this to target things [class^="MuiSvgIcon-root"], but maybe i can access the class through props, still messing with it. Anyway, here is the button.

import React from "react";
import { Button as MaterialButton, ButtonProps } from "@material-ui/core";
import styled from "styled-components";
import { ThemeProvider } from "@material-ui/core/styles";
import theme from "../../../theme";

export interface MyButtonProps extends ButtonProps {
  error?: boolean;
  target?: string;
}

const StyledButton = styled(MaterialButton)`
  &.error {
    background: ${theme.palette.error.main};
    color: #fff;
    &:hover {
      background: ${theme.palette.error.main};
    }
  }
`;

const Button = ({
  error,
  size,
  variant,
  endIcon,
  children,
  className,
  ...rest
}: MyButtonProps) => {
  if (className && error) {
    className += " error";
  } else if (!className && error) {
    className = "error";
  }

  return (
    <ThemeProvider theme={theme}>
      <StyledButton
        {...rest}
        variant={variant}
        size={size}
        endIcon={endIcon}
        className={className}
      >
        {children}
      </StyledButton>
    </ThemeProvider>
  );
};

export default Button;

I guess each component will need to be wrapped.

like image 69
Joe Madden Avatar answered Sep 08 '25 00:09

Joe Madden