npm package: @jiayouzuo/vite-plugin-css-scope
Description: Vite 插件：CSS 作用域隔离，解决微前端和模块联邦中的样式冲突问题
Author: jiayouzuo
Latest version: 0.1.6

# @jiayouzuo/vite-plugin-css-scope

Vite 插件：CSS 作用域隔离，解决微前端和模块联邦中的样式冲突问题。

## 功能特性

- **CSS 选择器包裹**：`.btn` → `[data-scope-appProcess="1"] .btn`
- **JSX 自动注入**：自动给模块联邦暴露的组件父元素添加作用域属性
- **HTML 自动注入**：自动给 `<body>` 添加作用域属性
- **Portal 容器处理**：自动处理 antd Modal、Drawer、Dropdown、Select、Tooltip、Message、Notification 等全局挂载组件
- **智能过滤**：自动跳过 `:root`、`html`、`body`、`@keyframes` 等全局选择器
- **HOC 支持**：支持 `forwardRef`、`memo` 等高阶组件
- **多格式支持**：CSS、Less、SCSS、Sass、JSX、TSX

## 安装

```bash
npm install @jiayouzuo/vite-plugin-css-scope -D
# 或
pnpm add @jiayouzuo/vite-plugin-css-scope -D
```

## 使用方法

```typescript
// vite.config.ts
import { defineConfig } from 'vite';
import cssScopePlugin from '@jiayouzuo/vite-plugin-css-scope';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [
    // ⚠️ 重要：cssScopePlugin 必须放在 react 插件之前
    cssScopePlugin({
      scope: 'appProcess',                              // 作用域名称
      include: ['src/', 'node_modules/@designable/'],   // 要处理的目录
      exclude: ['node_modules/antd']                    // 排除的目录（可选）
    }),
    react()
  ]
});
```

## 配置选项

| 参数 | 类型 | 必填 | 说明 |
|-----|------|-----|------|
| `scope` | `string` | 是 | 作用域名称，会生成 `data-scope-{scope}="1"` 属性选择器 |
| `include` | `string[]` | 是 | 要处理的目录列表（相对于项目根目录） |
| `exclude` | `string[]` | 否 | 排除的目录或文件 |

## 效果示例

### CSS 选择器包裹

```css
/* 原代码 */
.btn { color: red; }
.card, .panel { padding: 10px; }

/* 转换后 */
[data-scope-appProcess="1"] .btn { color: red; }
[data-scope-appProcess="1"] .card, [data-scope-appProcess="1"] .panel { padding: 10px; }
```

### JSX 组件自动注入（模块联邦）

配合模块联邦使用时，暴露的组件会自动注入作用域逻辑：

```jsx
// 原代码
function FormDesigner() {
  return <div>表单设计器</div>;
}

// 自动转换后
function FormDesigner() {
  const __scopeRefCallback = (__el) => {
    if (__el) {
      const __parent = __el.parentElement;
      if (__parent && !__parent.hasAttribute("data-scope-appProcess")) {
        __parent.setAttribute("data-scope-appProcess", "1");
      }
    }
  };

  return (
    <>
      <div ref={__scopeRefCallback} style={{width: 0, height: 0, overflow: 'hidden'}} />
      <div>表单设计器</div>
    </>
  );
}
```

### HTML 自动注入

```html
<!-- 原代码 -->
<body>

<!-- 转换后 -->
<body data-scope-appProcess="1">
```

### Portal 容器自动处理

antd 的 Modal、Drawer、Dropdown、Select、Tooltip、Message、Notification 等组件会将弹层挂载到 `document.body`，插件会自动处理这些 Portal 容器：

- `@rc-component/portal` - Modal、Drawer
- `rc-trigger` - Dropdown、Select、Tooltip、Popover 等
- `rc-notification` - Message、Notification

### 自动跳过的选择器

```css
/* 这些选择器保持原样，不会被包裹 */
:root { --color: red; }
html { font-size: 16px; }
body { margin: 0; }
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }
```

## 适用场景

1. **模块联邦样式隔离**：主应用（antd 5.x）和远端应用（antd 4.x）样式冲突
2. **微前端样式隔离**：多个子应用样式互不干扰
3. **第三方组件库隔离**：如 @designable 等组件库的样式隔离

## 工作原理

1. **CSS 处理**：使用 PostCSS 遍历所有规则，给选择器外层包裹 `[data-scope-xxx="1"]` 属性选择器
2. **JSX 处理**：使用 Babel AST 解析，注入回调 ref，通过辅助 div 获取父元素并添加作用域属性
3. **HTML 注入**：通过 Vite 的 `transformIndexHtml` 钩子给 `<body>` 自动加上作用域属性
4. **Portal 处理**：拦截 antd rc-* 组件的容器创建代码，自动注入作用域属性

## License

MIT