@jiayouzuo/vite-plugin-css-scope
v0.1.9
Published
Vite 插件:CSS 作用域隔离,解决微前端和模块联邦中的样式冲突问题
Maintainers
Readme
@jiayouzuo/vite-plugin-css-scope
Vite 插件:CSS 作用域隔离,解决微前端和模块联邦中的样式冲突问题。
功能特性
- CSS 选择器包裹:
.btn→[data-scope-appProcess="1"] .btn - 组件型 MF 自动注入:自动给模块联邦暴露的组件父元素添加作用域属性
- 路由型 MF 自动注入:按路由对象结构处理
element、errorElement的直接 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
安装
npm install @jiayouzuo/vite-plugin-css-scope -D
# 或
pnpm add @jiayouzuo/vite-plugin-css-scope -D使用方法
// 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 选择器包裹
/* 原代码 */
.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; }作用域只来自已有的 scope 配置,不需要增加 scopeRoots,也不需要业务组件
硬编码属性或 class。
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>
</>
);
}路由型 MF 自动注入
插件会读取 MF exposes 的真实模块路径,只处理精确匹配的 JSX/TSX 模块。
路由工厂、变量和文件可以任意命名;插件根据路由对象结构识别直接 JSX:
export function buildRoutes() {
return createRoutes({
element: <RuntimeLayout />,
errorElement: <ErrorPage />,
children: [
{ path: 'home', element: <Home /> },
],
});
}转换后每个路由渲染字段都使用与组件型 MF 相同的 Fragment + 隐藏 div ref
结构,把 data-scope-* 加到 React 实际挂载的父层。普通业务对象不会因为只有
一个 element 字段而被处理。
element: createAtRuntime() 这类运行时动态值无法由构建期 AST 安全展开,插件
会保留原代码并输出明确警告。没有 MF exposes 的项目不会执行 JSX 注入,HTML、
CSS 和 Portal 能力仍正常工作。
HTML 自动注入
<!-- 原代码 -->
<body>
<!-- 转换后 -->
<body data-scope-appProcess="1">Portal 容器自动处理
antd 的 Modal、Drawer、Dropdown、Select、Tooltip、Message、Notification 等组件会将弹层挂载到 document.body,插件会自动处理这些 Portal 容器:
@rc-component/portal- Modal、Drawerrc-trigger- Dropdown、Select、Tooltip、Popover 等rc-notification- Message、Notification
自动跳过的选择器
/* 这些选择器保持原样,不会被包裹 */
:root { --color: red; }
html { font-size: 16px; }
body { margin: 0; }
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }适用场景
- 模块联邦样式隔离:主应用(antd 5.x)和远端应用(antd 4.x)样式冲突
- 微前端样式隔离:多个子应用样式互不干扰
- 第三方组件库隔离:如 @designable 等组件库的样式隔离
工作原理
- CSS 处理:使用 PostCSS 遍历所有规则,生成
[data-scope-xxx="1"]属性入口 - JSX 处理:使用 Babel AST 解析组件返回值和路由对象,注入回调 ref,通过辅助 div 获取父元素并添加作用域属性
- HTML 注入:通过 Vite 的
transformIndexHtml钩子给<body>自动加上作用域属性 - Portal 处理:拦截 antd rc-* 组件的容器创建代码,自动注入作用域属性
License
MIT
