Search code examples
reactjstypescriptmaterial-uirolluppeer-dependencies

Is it possible to have Material UI as peerDependency but keep its types as DevDependency?


Is it possible to have Material UI as peerDependency but keep its types as DevDependency?

I am building a component library using React + Typescript and the components are based on Material UI library, with Rollup as module bundler.

Here is an example of my IInputProps type extending Material UI TextFieldProps type.

import { TextFieldProps } from "@material-ui/core";

export type IInputProps = TextFieldProps & {...}

My goal is to set Material UI packages as a peerDependency, so it will use the material-ui package installed on the target project. I inserted the Material UI as peerDependency and set up rollup with peerDepsExternal plugin. When I tried to build the package, it throws the following error:

Cannot find module '@material-ui/core' or its corresponding type declarations.

The reason is related to this answer (What's the relationship of @material-ui/core and @types/material-ui?). Material-UI package contains its own type definitions (*.d.ts files), so when I set it as peerDependency, the types/interfaces are missing. To solve this problem, I followed this solution (https://github.com/ezolenko/rollup-plugin-typescript2/issues/198) declaring each module on a src/@types/material-ui/index.d.ts file, but it raised another problem: I cannot use material-ui types/interfaces anymore.

With @material-ui/core declared on my src/@types/material-ui/index.d.ts file, the code points this error below.

Cannot use namespace 'TextFieldProps' as a type.ts(2709)

Exported type alias 'IInputProps' has or is using private name 'TextFieldProps'.ts(4081)

Now, I can only see these 2 solutions:

  1. Keep the entire material ui packages on my library and lose in the package size:
Library with Material UI packages as peerDependency
npm notice package size:  101.0 kB
npm notice unpacked size: 493.6 kB

Library with Material UI packages
npm notice package size:  1.2 MB
npm notice unpacked size: 6.0 MB
  1. Use Material UI as peerDependency, but lose the Material UI types/interfaces and lint (by adding a property to my types/interfaces that accept any prop - TypeScript interface that allows other properties).
[x:string]:any

So, I would like to know if there is any way to have Material UI as peerDependency but keep its types as devDependencies, so I can bundle it with Material UI as peerDependency and also use its types on my package?

My configurations are following below:

src/@types/material-ui/index.d.ts

declare module "@material-ui/core";

rollup.config.js

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

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(),
    image(),
    typescript({ useTsconfigDeclarationDir: true })
  ]
};

tsconfig.json

{
  "compilerOptions": {
    "rootDir": "src",
    "declaration": true,
    "declarationDir": "build",
    "module": "esnext",
    "target": "es5",
    "lib": ["es6", "dom", "es2016", "es2017"],
    "sourceMap": true,
    "jsx": "react",
    "moduleResolution": "node",
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "typeRoots": ["./src/@types"]
  },
  "include": ["src/**/*"],
  "exclude": [
    "node_modules",
    "build",
    "storybook-static",
    "src/**/*.stories.tsx",
    "src/**/*.test.tsx"
  ]
}

package.json

...
"main": "build/index.js",
  "module": "build/index.esm.js",
...
,
  "peerDependencies": {
    "@material-ui/core": "^4.11.4",
    "react": "^16.8.0",
    "react-dom": "^16.8.0",
  },
...

Solution

  • I solved the problem by setting all my peerDependencies also as my devDependencies.

    So, my package json was setting as below:

    "peerDependencies": {
        "@material-ui/core": "^4.11.4",
        "react": "^16.8.0",
        "react-dom": "^16.8.0",
    },
    "devDependencies": {
        "@material-ui/core": "^4.11.4",
        "react": "^16.8.0",
        "react-dom": "^16.8.0",
    ...
    

    Then I could get rid off some configurations:

    1. I deleted my 'src/@types/material-ui/index.d.ts'
    2. I removed ' "typeRoots": ["./src/@types"]' from my tsconfig.json

    All the others configurations remained the same.

    reference: https://github.com/HarveyD/react-component-library/issues/40