Skip to content

Commit f0ea638

Browse files
committed
Randomize prod classnames
1 parent a2e9c7b commit f0ea638

3 files changed

Lines changed: 87 additions & 7 deletions

File tree

learnings/css-issue-in-mfe.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
🔹 What is CSS Scoping in MFE?
2+
3+
CSS scoping means ensuring that the styles of one microfrontend do not accidentally affect or “leak” into another microfrontend (or the host container).
4+
5+
In traditional web apps, CSS is global by default. If two apps have a `.btn` class, their styles can conflict. In MFEs, since multiple apps (built with React, Angular, Vue, etc.) are composed together, this becomes a serious problem.
6+
7+
So CSS scoping is the practice of isolating styles of each microfrontend, so they apply only to that app’s components.
8+
9+
🔹 Why do we need it in MFE?
10+
11+
1. Avoid Style Collisions
12+
13+
- Different teams may use the same class names (.header, .btn, .card) in their MFEs. Without scoping, these styles could override each other.
14+
15+
2. Independent Development
16+
17+
- Teams can freely choose their UI libraries/frameworks (e.g., Tailwind in one MFE, Material UI in another) without worrying about breaking each other’s design.
18+
19+
3. Predictable UI
20+
21+
- The look and feel of each MFE remains consistent and stable, no matter how many apps are composed in the container.
22+
23+
4. Easier Maintenance
24+
25+
- Debugging becomes simpler since you know styles belong only to their respective MFE.
26+
27+
🔹 Ways to Implement CSS Scoping in MFE
28+
29+
1. CSS Modules
30+
31+
- Class names are automatically made unique at build time.
32+
33+
```css
34+
/* button.module.css */
35+
.btn {
36+
background: blue;
37+
}
38+
```
39+
```tsx
40+
import styles from './button.module.css';
41+
<button className={styles.btn}>Click</button>
42+
```
43+
44+
2. CSS-in-JS (Styled Components, Emotion)
45+
46+
- Generates unique class names at runtime.
47+
48+
```tsx
49+
const Button = styled.button`
50+
background: blue;
51+
`;
52+
```
53+
3. Shadow DOM (Web Components)
54+
55+
- Native browser encapsulation that completely isolates styles.
56+
57+
4. Namespace Conventions
58+
59+
- Prefixing class names with app name (`marketing-btn`, `dashboard-header`). Not as strong, but works.
60+
61+
5. PostCSS/Scoped CSS
62+
63+
- Using tools to automatically namespace CSS selectors per MFE.
64+
65+
Summary:
66+
67+
CSS scoping in MFEs is about style isolation. Without it, one microfrontend’s CSS could break another’s layout. With it, each MFE behaves like a standalone app with its own style boundary.

packages/container/src/App.js

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,25 @@
11
import React from "react";
2-
import {BrowserRouter} from "react-router-dom";
2+
import { BrowserRouter } from "react-router-dom";
3+
import {
4+
StylesProvider,
5+
createGenerateClassName,
6+
} from "@material-ui/core/styles";
37
import MarketingApp from "./components/MarketingApp";
48
import Header from "./components/Header";
59

10+
const generateClassName = createGenerateClassName({
11+
productionPrefix: "co", // co for container
12+
});
13+
614
export default () => {
715
return (
816
<BrowserRouter>
9-
<div>
10-
<Header/>
11-
<MarketingApp />
12-
</div>
17+
<StylesProvider generateClassName={generateClassName}>
18+
<div>
19+
<Header />
20+
<MarketingApp />
21+
</div>
22+
</StylesProvider>
1323
</BrowserRouter>
1424
);
1525
};

packages/marketing/src/App.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
import React from "react";
22
import {Switch,Route, BrowserRouter} from "react-router-dom";
3-
import {StylesProvider} from "@material-ui/core/styles";
3+
import {StylesProvider, createGenerateClassName} from "@material-ui/core/styles";
44

55
import Landing from "./components/Landing";
66
import Pricing from "./components/Pricing";
77

8+
const generateClassName = createGenerateClassName({
9+
productionPrefix: "ma",
10+
})
811

912
export default () => {
1013

1114
return (
1215
<div>
13-
<StylesProvider injectFirst>
16+
<StylesProvider generateClassName={generateClassName}>
1417
<BrowserRouter>
1518
<Switch>
1619
<Route exact path="/" component={Landing} />

0 commit comments

Comments
 (0)