微前端 - qiankun 入门到实践——第八节:微前端中的样式隔离与共享

262 阅读3分钟

在微前端架构中,子应用的样式隔离和共享是一个重要问题。我们需要确保子应用的样式不会互相干扰,同时也需要支持共享一些全局样式。

样式隔离

样式隔离可以通过多种方式实现,包括CSS Modules、Shadow DOM、以及CSS-in-JS等方法。

  1. CSS Modules

CSS Modules通过生成唯一的类名来确保样式的局部性,从而避免样式冲突。

  • 在Vite中配置CSS Modules
  1. 创建一个React组件并使用CSS Modules:

    // src/components/MyComponent.module.css .myComponent { color: blue; }

    // src/components/MyComponent.tsx import React from 'react'; import styles from './MyComponent.module.css';

    const MyComponent = () => (

    This is a CSS Module component.
    );

    export default MyComponent;

  • 在Vite项目中启用CSS Modules
  1. Vite默认支持CSS Modules,因此不需要额外配置。

  2. Shadow DOM

Shadow DOM是一种浏览器原生技术,它允许我们将样式封装在组件内部,避免与外部样式冲突。

  • 使用Shadow DOM
  1. 创建一个自定义元素并将其挂载到Shadow DOM:

    // src/components/ShadowComponent.tsx import React, { useEffect, useRef } from 'react';

    const ShadowComponent = () => { const shadowRootRef = useRef<ShadowRoot | null>(null);

    useEffect(() => { if (shadowRootRef.current) { const shadowRoot = shadowRootRef.current; const style = document.createElement('style'); style.textContent = .shadowComponent { color: red; } ; shadowRoot.appendChild(style);

      const div = document.createElement('div');
      div.className = 'shadowComponent';
      div.textContent = 'This is inside Shadow DOM';
      shadowRoot.appendChild(div);
    }
    

    }, []);

    return <div ref={el => { if (el && !shadowRootRef.current) { shadowRootRef.current = el.attachShadow({ mode: 'open' }); } }} />; };

    export default ShadowComponent;

  2. CSS-in-JS

CSS-in-JS允许我们将样式定义在JavaScript文件中,并动态地将其应用到组件中。

  • 使用Styled Components
  1. 安装Styled Components:

    npm install styled-components @types/styled-components

  2. 创建一个使用Styled Components的React组件:

    // src/components/StyledComponent.tsx import React from 'react'; import styled from 'styled-components';

    const StyledDiv = styled.div color: green;;

    const StyledComponent = () => ( This is a styled component. );

    export default StyledComponent;

样式共享

在微前端架构中,有时需要共享一些全局样式,例如重置样式或公共UI组件的样式。我们可以通过多种方式实现样式共享。

  1. 全局样式

将全局样式定义在主应用中,并确保所有子应用都能引用这些样式。

  • 定义全局样式

    /* src/styles/global.css */ body { margin: 0; font-family: Arial, sans-serif; }

  • 在主应用中引入全局样式

    // src/main.tsx import './styles/global.css';

  1. 共享样式库

    创建一个独立的样式库项目,并将其作为依赖引入到主应用和子应用中。

    1. 创建样式库

    2. 创建一个新的项目并定义共享样式:

    /* styles-library/src/styles.css */ .shared-button { background-color: blue; color: white; padding: 10px; border: none; border-radius: 5px; }

  • 在主应用和子应用中引入样式库
  1. 将样式库发布到npm,并在主应用和子应用中安装:

    npm install styles-library

    // src/main.tsx import 'styles-library/styles.css';

  2. CSS Variables

使用CSS Variables(CSS自定义属性)来定义和共享样式。

  • 定义CSS Variables

    /* src/styles/variables.css */ :root { --primary-color: #4CAF50; --secondary-color: #FFC107; }

  • 在组件中使用CSS Variables

    // src/components/VariableComponent.tsx import React from 'react'; import './variables.css';

    const VariableComponent = () => (

    This is using CSS variables.
    );

    export default VariableComponent;

示例代码

以下是一个完整的示例,包括主应用和子应用的样式隔离与共享配置。

主应用

// src/App.tsx
import React, { useEffect } from 'react';
import { Link, Route, Routes } from 'react-router-dom';
import { registerMicroApps, start } from 'qiankun';
import Home from './pages/Home';
import About from './pages/About';
import './styles/global.css';

const App = () => {
  useEffect(() => {
    registerMicroApps([
      {
        name: 'sub-app-1',
        entry: '//localhost:7100', // 子应用入口
        container: '#subapp-container',
        activeRule: '/subapp1',
      },
    ]);
    start();
  }, []);

  return (
    <div>
      <nav>
        <ul>
          <li><Link to="/">Home</Link></li>
          <li><Link to="/about">About</Link></li>
          <li><Link to="/subapp1">Sub App 1</Link></li>
        </ul>
      </nav>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="/subapp1/*" element={<div id="subapp-container"></div>} />
      </Routes>
    </div>
  );
};

export default App;

子应用

// src/main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import './styles/global.css'; // 引入全局样式

function render(props: any) {
  const { container } = props;
  const root = ReactDOM.createRoot(container ? container.querySelector('#root') : document.querySelector('#root'));
  root.render(
    <React.StrictMode>
      <App />
    </React.StrictMode>
  );
}

if (!window.__POWERED_BY_QIANKUN__) {
  render({});
}

export async function bootstrap() {
  console.log('React app bootstraped');
}

export async function mount(props: any) {
  render(props);
}

export async function unmount(props: any) {
  const { container } = props;
  const root = container ? container.querySelector('#root') : document.querySelector('#root');
  ReactDOM.unmountComponentAtNode(root);
}

通过本节内容,我们了解了如何在微前端架构中实现样式隔离与共享。我们探讨了CSS Modules、Shadow DOM、CSS-in-JS等样式隔离方法,以及全局样式、共享样式库和CSS Variables等样式共享策略。接下来,我们将继续探索微前端架构中的性能优化技术。