Custom ESLint Import Rule for MaterialUI - reactjs

I have a project in React, using Material UI, and I am applying one of their suggested methods to reduce my bundle size.
Basically, I need to install the babel-plugin-transform-imports package and update the way we import components:
// Replace this (Option 1):
import Button from "#material-ui/core/Button";
// Whith this (Option 2):
import { Button } from "#material-ui/core";
Everything is working fine, however, I would like to prevent the "wrong" imports (Option 1) in the future.
Is there a way to customize a ESLint rule that will force the Option 2 import ONLY when importing from the Material UI package?
I was reading about creating a custom ESLint rule, but would prefer to avoid that route.

To my knowledge, custom is your only way to go. The only difference between these syntax is importing the default export or a named export. So if you want to prevent default imports specifically for the material-ui packages, you would need to create a custom eslint rule that looked at import statements AND match against material-ui as you don't want to error on all default imports.

After some research, I found that Material UI created a package with their own custom ESLint rules:
NPM Package:
https://www.npmjs.com/package/eslint-plugin-material-ui
GitHub page:
https://github.com/mui-org/material-ui/tree/master/packages/eslint-plugin-material-ui
They have a rule to solve my issue (restricted-path-imports), but that is not published yet. When they publish it, that may be the best way to go for me.
Discussion about publishing the rule:
https://github.com/mui-org/material-ui/issues/15610#issuecomment-512804075

UPDATE 2022
#kajirikajiri actually made eslint plugin exactly for this!
https://github.com/kajirikajiri/eslint-plugin-mui-path-imports

Related

Import svg as component using preact and vite

I'm currently working on an application using preact, tailwindcss and vite. Unfortunately, importing svgs seems to be a bit problematic.
There is a separate repository that only contains the svg resources.
My original plan was to just import them as components as I was used to do it in classic react with webpack applications using SVGR and the following syntax:
import { ReactComponent as Search } from 'assets/icons/search-lg.svg';
This won't work for (at least) two reasons. One being preact the other one being the lack of SVGR.
I then proceeded to give vite-plugin-svgr a try by importing it in my vite.config.js.
plugins: [svgr({ svgrOptions: { jsxRuntime: 'classic-preact' } }), preact(), tsconfigPaths()],
It kinda works using the following import syntax:
import Search from 'assets/icons/search-lg.svg?component';
Unfortunately this raises the following error which I couldn't manage to work around besides ignoring it which is not really an option:
TS2307: Cannot find module 'assets/icons/search-lg.svg?component' or its corresponding type declarations
The alternate plan would now be to create a wrapper component that just imports the svg from the given path and create a component from it myself. This would also simplify styling it with tailwind.
Unfortunately I fail to import the file in a way I can wrap it with <svg> tags. Using <img> is not really an option because I need to be able to manipulate the svg.
So, does anybody have an idea how to either
correctly use the component import in my setup
create a preact component that imports an svg from a file and still is customizable
Thanks in advance!
I finally got it to work by using vite-plugin-svgr. In the end adding /// <reference types="vite-plugin-svgr/client" /> to vite-env.d.ts made the compiler happy.
I can now use the good 'ol syntax:
import { ReactComponent as Search } from 'assets/icons/search-lg.svg';
Thanks to #user-28 for pointing me in the right direction!

How to import CSS toolkit supplied by MaterialUI (MUI)

I have used MUI on my website.
While playing with the devtools I saw many class associated with the MUI components.
Does MUI have CSS for its default components like Menu?
The layout I have with the MUI component lacks organization.
Something like
import '#mui/dist/mui.css';
as this doesnot work.
This documentation page from MUI provides your answer and more.
https://www.muicss.com/docs/v1/react/introduction
After installing it with npm (or other package manager)
npm install --save muicss
You can import either individual components as shown in the documentation
// Access all components from `muicss/react` module
import { Appbar, Button, Container } from 'muicss/react';
// Access components individually for smaller build files (RECOMMENDED)
import Appbar from 'muicss/lib/react/appbar';
import Button from 'muicss/lib/react/button';
import Container from 'muicss/lib/react/container'
Or as per your use case you can import the various css files provided in the node module directly. For example
import 'muicss/css/mui.css
Or it appears that they also provide sass
import 'muicss/lib/sass/mui/*the_component_you_want*'
The MUICSS package appears to be designed for a la carte use of components so If you're using the MUI 'framework' you may want to consider a way to avoid bloat when importing/installing from both packages.

Importing only one component from Material UI

need a Stepper component from somewhere and the only adequate one I found was the MUI one. But my app uses react-bootstrap and I don't have it. In this post (Is it possible to install a package that contains only one component of Material-UI? ) the guys have given a package where you can import only the component you need, but for some reason I am required to do npm config set '#bit:registry' https://node.bit.dev which I am not okay with since I want everyone to be able to just do an npm install without additional configuration. Is there a workaround around that and is it actually okay to install the whole MUI kit and import just the Stepper ?
If you're using ES6 modules and a bundler that supports tree-shaking (webpack >= 2.x, parcel with a flag) you can safely use named imports and still get an optimised bundle size automatically.
You can use path imports to avoid pulling in unused modules. For instance, use:
import Stepper from '#material-ui/core/Stepper';
instead of
import { Stepper } from '#material-ui/core';
Read more about minimizing bundle size here
Please, let me know if it works or not )

WebStorm/IntelliJ autosuggest doesn't recognize named imports

I tried installing extra TypeScript libraries as suggested by others. My project JavaScript Language is set to ReactJSX. However when using the auto import, it only imports modules as if default imports. It recognizes the correct package, just doesn't do a named import.
The second image will fail as it should be a named import.
Looks similar to https://youtrack.jetbrains.com/issue/WEB-47925 that is planned to be fixed in 2020.3.
BTW, according to the documentation, the preferred way to import react-bootstrap components is using the default imports like import Button from 'react-bootstrap/Button';

How to combine multiple classNames in React?

I'm writing a small React app with Create-React-App. For simple styling tweaks I use tachyons-css. Due to frequent reappearing CSS styling issues I recently switched from classic CSS styling to CSS modules (also valid question for SCSS). Now I wonder if there is a way to still use both - CSS modules and tachyons styling - even though it is not possible anymore to just add an additional "classic" className to the CSS module styles object.
Before using CSS modules I used to define a class and tachyons styling (padding5 in this example) by having multiple classNames.
For example:
<ExampleComponent className="examplecomponentstyle pa5"/>
When using CSS modules the CSS class definition will now look like this:
<ExampleComponent className={styles.examplecomponentstyle}/>
How can this syntax now be combined with the previous usage of the tachyons styling? Is there something like this that could work?:
<ExampleComponent className={styles.examplecomponentstyle & "pa5"}/>
Thanks a lot!
UPDATE from 05-Sep-19:
The clsx package is exactly doing what I was trying to achieve. After installing clsx
npm install --save clsx
the ExampleComponent can then e.g. be styled using clsx like this:
<ExampleComponent className={clsx(styles.examplecomponentstyle, "pa5 bg-yellow")}/>
UPDATE from 17-May-20:
As Sandip pointed out the ClassNames package can as well as the clsx package be used to achieve the same behaviour. The number of weekly downloads of both packages even indicates that ClassNames is much more frequently used than CLSX (~5.2 mio vs ~1.6 mio weekly downloads as of May 17 2020). This link on github discusses the performance differences between the two packages.
Without any package:
className={[styles.examplecomponentstyle, "pa5"].join(" ")};
Like you already mentioned, the package clsx is pretty good:
className={clsx(styles.examplecomponentstyle, "pa5 bg-yellow")}
When using CSS modules, you can combine classes like this
import styles from "./styles.module.css";
import "./index.css";
...
<div className={`${style.header} ${style.headerLight} container`}>
...

Resources