@jiayouzuo/vite-plugin-css-scope 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +127 -0
- package/dist/index.js +90 -19
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# @jiayouzuo/vite-plugin-css-scope
|
|
2
|
+
|
|
3
|
+
Vite 插件:CSS 作用域隔离,解决微前端和模块联邦中的样式冲突问题。
|
|
4
|
+
|
|
5
|
+
## 功能特性
|
|
6
|
+
|
|
7
|
+
- **CSS 选择器包裹**:`.btn` → `.appProcess .btn`
|
|
8
|
+
- **JSX 自动注入**:自动给模块联邦暴露的组件父元素添加作用域 className
|
|
9
|
+
- **HTML 自动注入**:自动给 `<body>` 添加作用域类名
|
|
10
|
+
- **智能过滤**:自动跳过 `:root`、`html`、`body`、`@keyframes` 等全局选择器
|
|
11
|
+
- **HOC 支持**:支持 `forwardRef`、`memo` 等高阶组件
|
|
12
|
+
- **多格式支持**:CSS、Less、SCSS、Sass、JSX、TSX
|
|
13
|
+
|
|
14
|
+
## 安装
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @jiayouzuo/vite-plugin-css-scope -D
|
|
18
|
+
# 或
|
|
19
|
+
pnpm add @jiayouzuo/vite-plugin-css-scope -D
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## 使用方法
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
// vite.config.ts
|
|
26
|
+
import { defineConfig } from 'vite';
|
|
27
|
+
import cssScopePlugin from '@jiayouzuo/vite-plugin-css-scope';
|
|
28
|
+
|
|
29
|
+
export default defineConfig({
|
|
30
|
+
plugins: [
|
|
31
|
+
cssScopePlugin({
|
|
32
|
+
scope: 'appProcess', // 作用域类名
|
|
33
|
+
include: ['src/', 'node_modules/@designable/'], // 要处理的目录
|
|
34
|
+
exclude: ['node_modules/antd'] // 排除的目录(可选)
|
|
35
|
+
})
|
|
36
|
+
]
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## 配置选项
|
|
41
|
+
|
|
42
|
+
| 参数 | 类型 | 必填 | 说明 |
|
|
43
|
+
|-----|------|-----|------|
|
|
44
|
+
| `scope` | `string` | 是 | 作用域类名,会加到 body 上,也会作为 CSS 选择器的父级 |
|
|
45
|
+
| `include` | `string[]` | 是 | 要处理的目录列表(相对于项目根目录) |
|
|
46
|
+
| `exclude` | `string[]` | 否 | 排除的目录或文件 |
|
|
47
|
+
|
|
48
|
+
## 效果示例
|
|
49
|
+
|
|
50
|
+
### CSS 选择器包裹
|
|
51
|
+
|
|
52
|
+
```css
|
|
53
|
+
/* 原代码 */
|
|
54
|
+
.btn { color: red; }
|
|
55
|
+
.card, .panel { padding: 10px; }
|
|
56
|
+
|
|
57
|
+
/* 转换后 */
|
|
58
|
+
.appProcess .btn { color: red; }
|
|
59
|
+
.appProcess .card, .appProcess .panel { padding: 10px; }
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### JSX 组件自动注入(模块联邦)
|
|
63
|
+
|
|
64
|
+
配合模块联邦使用时,暴露的组件会自动注入作用域逻辑:
|
|
65
|
+
|
|
66
|
+
```jsx
|
|
67
|
+
// 原代码
|
|
68
|
+
function FormDesigner() {
|
|
69
|
+
return <div>表单设计器</div>;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// 自动转换后
|
|
73
|
+
function FormDesigner() {
|
|
74
|
+
const __scopeRefCallback = (__el) => {
|
|
75
|
+
if (__el) {
|
|
76
|
+
const __parent = __el.parentElement;
|
|
77
|
+
if (__parent) {
|
|
78
|
+
__parent.classList.add("appProcess");
|
|
79
|
+
__el.remove();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<>
|
|
86
|
+
<div ref={__scopeRefCallback} style={{width: 0, height: 0, overflow: 'hidden'}} />
|
|
87
|
+
<div>表单设计器</div>
|
|
88
|
+
</>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### HTML 自动注入
|
|
94
|
+
|
|
95
|
+
```html
|
|
96
|
+
<!-- 原代码 -->
|
|
97
|
+
<body>
|
|
98
|
+
|
|
99
|
+
<!-- 转换后 -->
|
|
100
|
+
<body class="appProcess">
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### 自动跳过的选择器
|
|
104
|
+
|
|
105
|
+
```css
|
|
106
|
+
/* 这些选择器保持原样,不会被包裹 */
|
|
107
|
+
:root { --color: red; }
|
|
108
|
+
html { font-size: 16px; }
|
|
109
|
+
body { margin: 0; }
|
|
110
|
+
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## 适用场景
|
|
114
|
+
|
|
115
|
+
1. **模块联邦样式隔离**:主应用(antd 5.x)和远端应用(antd 4.x)样式冲突
|
|
116
|
+
2. **微前端样式隔离**:多个子应用样式互不干扰
|
|
117
|
+
3. **第三方组件库隔离**:如 @designable 等组件库的样式隔离
|
|
118
|
+
|
|
119
|
+
## 工作原理
|
|
120
|
+
|
|
121
|
+
1. **CSS 处理**:使用 PostCSS 遍历所有规则,给选择器外层包裹 `.scope` 父级
|
|
122
|
+
2. **JSX 处理**:使用 Babel AST 解析,注入回调 ref,通过辅助 div 获取父元素并添加作用域 className
|
|
123
|
+
3. **HTML 注入**:通过 Vite 的 `transformIndexHtml` 钩子给 `<body>` 自动加上作用域类名
|
|
124
|
+
|
|
125
|
+
## License
|
|
126
|
+
|
|
127
|
+
MIT
|
package/dist/index.js
CHANGED
|
@@ -78,7 +78,7 @@ function transformSelectors(selector, scope) {
|
|
|
78
78
|
return selector.split(",").map((sel) => {
|
|
79
79
|
const trimmed = sel.trim();
|
|
80
80
|
if (isGlobalSelector(trimmed)) return sel;
|
|
81
|
-
return
|
|
81
|
+
return `[data-scope-${scope}="1"] ${sel}`;
|
|
82
82
|
}).join(", ");
|
|
83
83
|
}
|
|
84
84
|
function isGlobalSelector(selector) {
|
|
@@ -158,6 +158,7 @@ function injectScopeLogic(path, scopeClassName) {
|
|
|
158
158
|
wrapReturnStatements(path);
|
|
159
159
|
}
|
|
160
160
|
function createRefCallbackDeclaration(scopeClassName) {
|
|
161
|
+
const attrName = `data-scope-${scopeClassName}`;
|
|
161
162
|
return t2.variableDeclaration("const", [
|
|
162
163
|
t2.variableDeclarator(
|
|
163
164
|
t2.identifier("__scopeRefCallback"),
|
|
@@ -175,23 +176,26 @@ function createRefCallbackDeclaration(scopeClassName) {
|
|
|
175
176
|
t2.memberExpression(t2.identifier("__el"), t2.identifier("parentElement"))
|
|
176
177
|
)
|
|
177
178
|
]),
|
|
178
|
-
// if (__parent) { ... }
|
|
179
|
+
// if (__parent && !__parent.hasAttribute("data-scope-xxx")) { ... }
|
|
179
180
|
t2.ifStatement(
|
|
180
|
-
t2.
|
|
181
|
+
t2.logicalExpression(
|
|
182
|
+
"&&",
|
|
183
|
+
t2.identifier("__parent"),
|
|
184
|
+
t2.unaryExpression(
|
|
185
|
+
"!",
|
|
186
|
+
t2.callExpression(
|
|
187
|
+
t2.memberExpression(t2.identifier("__parent"), t2.identifier("hasAttribute")),
|
|
188
|
+
[t2.stringLiteral(attrName)]
|
|
189
|
+
)
|
|
190
|
+
)
|
|
191
|
+
),
|
|
181
192
|
t2.blockStatement([
|
|
182
|
-
// __parent.
|
|
193
|
+
// __parent.setAttribute("data-scope-xxx", "1");
|
|
183
194
|
t2.expressionStatement(
|
|
184
195
|
t2.callExpression(
|
|
185
|
-
t2.memberExpression(
|
|
186
|
-
|
|
187
|
-
t2.identifier("add")
|
|
188
|
-
),
|
|
189
|
-
[t2.stringLiteral(scopeClassName)]
|
|
196
|
+
t2.memberExpression(t2.identifier("__parent"), t2.identifier("setAttribute")),
|
|
197
|
+
[t2.stringLiteral(attrName), t2.stringLiteral("1")]
|
|
190
198
|
)
|
|
191
|
-
),
|
|
192
|
-
// __el.remove();
|
|
193
|
-
t2.expressionStatement(
|
|
194
|
-
t2.callExpression(t2.memberExpression(t2.identifier("__el"), t2.identifier("remove")), [])
|
|
195
199
|
)
|
|
196
200
|
])
|
|
197
201
|
)
|
|
@@ -321,13 +325,73 @@ function transformComponent(code, filePath, scope) {
|
|
|
321
325
|
|
|
322
326
|
// src/html/transformer.ts
|
|
323
327
|
function transformHtml(html, scope) {
|
|
324
|
-
|
|
325
|
-
return html.replace(/(<body[^>]*\sclass\s*=\s*["'])([^"']*)/, `$1${scope} $2`);
|
|
326
|
-
}
|
|
328
|
+
const attrName = `data-scope-${scope}`;
|
|
327
329
|
if (/<body\s+[^>]*>/.test(html)) {
|
|
328
|
-
return html.replace(/(<body)(\s+[^>]*>)/, `$1
|
|
330
|
+
return html.replace(/(<body)(\s+[^>]*>)/, `$1 ${attrName}="1"$2`);
|
|
331
|
+
}
|
|
332
|
+
return html.replace("<body>", `<body ${attrName}="1">`);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// src/babel/portal-transform.ts
|
|
336
|
+
import { parse as parse2 } from "@babel/parser";
|
|
337
|
+
import traverseModule3 from "@babel/traverse";
|
|
338
|
+
import generateModule2 from "@babel/generator";
|
|
339
|
+
import * as t4 from "@babel/types";
|
|
340
|
+
var traverse3 = traverseModule3.default || traverseModule3;
|
|
341
|
+
var generate2 = generateModule2.default || generateModule2;
|
|
342
|
+
var PORTAL_FILES = [
|
|
343
|
+
// @rc-component/portal/es/useDom.js - Modal, Drawer
|
|
344
|
+
{ pattern: /@rc-component[\/\\]portal[\/\\].*useDom/, varName: "defaultEle" },
|
|
345
|
+
// rc-trigger/es/index.js - Dropdown, Select, Tooltip 等
|
|
346
|
+
{ pattern: /rc-trigger[\/\\].*index\.js/, varName: "popupContainer" },
|
|
347
|
+
// rc-notification/es/Notification.js - Message, Notification
|
|
348
|
+
{ pattern: /rc-notification[\/\\].*Notification\.js/, varName: "div" }
|
|
349
|
+
];
|
|
350
|
+
function isPortalFile(id) {
|
|
351
|
+
for (const { pattern, varName } of PORTAL_FILES) {
|
|
352
|
+
if (pattern.test(id)) {
|
|
353
|
+
return { match: true, varName };
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
return { match: false };
|
|
357
|
+
}
|
|
358
|
+
function transformPortal(code, id, scope, targetVarName) {
|
|
359
|
+
try {
|
|
360
|
+
const ast = parse2(code, {
|
|
361
|
+
sourceType: "module",
|
|
362
|
+
plugins: ["jsx"]
|
|
363
|
+
});
|
|
364
|
+
let modified = false;
|
|
365
|
+
traverse3(ast, {
|
|
366
|
+
VariableDeclarator(path) {
|
|
367
|
+
const init = path.node.init;
|
|
368
|
+
if (t4.isIdentifier(path.node.id) && path.node.id.name === targetVarName && t4.isCallExpression(init) && t4.isMemberExpression(init.callee) && t4.isIdentifier(init.callee.property, { name: "createElement" }) && init.arguments.length > 0 && t4.isStringLiteral(init.arguments[0], { value: "div" })) {
|
|
369
|
+
const parentDecl = path.parentPath;
|
|
370
|
+
if (t4.isVariableDeclaration(parentDecl.node)) {
|
|
371
|
+
const attrName = `data-scope-${scope}`;
|
|
372
|
+
parentDecl.insertAfter(
|
|
373
|
+
t4.expressionStatement(
|
|
374
|
+
t4.callExpression(
|
|
375
|
+
t4.memberExpression(t4.identifier(targetVarName), t4.identifier("setAttribute")),
|
|
376
|
+
[t4.stringLiteral(attrName), t4.stringLiteral("1")]
|
|
377
|
+
)
|
|
378
|
+
)
|
|
379
|
+
);
|
|
380
|
+
modified = true;
|
|
381
|
+
console.log(`[css-scope-plugin] \u6CE8\u5165 portal \u4F5C\u7528\u57DF: ${id.split(/[\/\\]/).pop()} -> ${targetVarName}.setAttribute("${attrName}", "1")`);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
if (modified) {
|
|
387
|
+
const result = generate2(ast, { retainLines: true, comments: true });
|
|
388
|
+
return result.code;
|
|
389
|
+
}
|
|
390
|
+
return null;
|
|
391
|
+
} catch (error) {
|
|
392
|
+
console.error(`[css-scope-plugin] portal \u8F6C\u6362\u5931\u8D25: ${id}`, error.message);
|
|
393
|
+
return null;
|
|
329
394
|
}
|
|
330
|
-
return html.replace("<body>", `<body class="${scope}">`);
|
|
331
395
|
}
|
|
332
396
|
|
|
333
397
|
// src/index.ts
|
|
@@ -364,9 +428,16 @@ function cssScopePlugin(options) {
|
|
|
364
428
|
};
|
|
365
429
|
},
|
|
366
430
|
/**
|
|
367
|
-
* 转换模块联邦暴露的 JSX/TSX 组件
|
|
431
|
+
* 转换模块联邦暴露的 JSX/TSX 组件 + antd portal 容器注入
|
|
368
432
|
*/
|
|
369
433
|
transform(code, id) {
|
|
434
|
+
const portalMatch = isPortalFile(id);
|
|
435
|
+
if (portalMatch.match && portalMatch.varName) {
|
|
436
|
+
const result = transformPortal(code, id, scope, portalMatch.varName);
|
|
437
|
+
if (result) {
|
|
438
|
+
return { code: result, map: null };
|
|
439
|
+
}
|
|
440
|
+
}
|
|
370
441
|
if (!/\.(jsx|tsx)$/.test(id)) return null;
|
|
371
442
|
const isExposed = exposedComponentPaths.some((exposedPath) => {
|
|
372
443
|
const normalizedPath = exposedPath.replace(/^\.\//, "");
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/path-matcher.ts","../src/utils/federation.ts","../src/postcss/scope-plugin.ts","../src/babel/transform.ts","../src/babel/hoc-detector.ts","../src/babel/scope-injector.ts","../src/html/transformer.ts","../src/index.ts"],"sourcesContent":["/**\n * @file 路径匹配工具\n * @description 判断文件路径是否需要处理\n */\n\n/**\n * 创建路径匹配器\n * @param include - 包含的路径模式\n * @param exclude - 排除的路径模式\n * @returns 匹配函数\n */\nexport function createPathMatcher(include: string[], exclude: string[]) {\n /**\n * 检查文件是否需要处理\n * @param filePath - 文件路径\n * @returns 是否需要处理\n */\n return function shouldTransform(filePath: string): boolean {\n // 优先检查排除列表\n for (const pattern of exclude) {\n if (filePath.includes(pattern)) {\n return false;\n }\n }\n\n // 检查包含列表\n for (const pattern of include) {\n if (filePath.includes(pattern)) {\n return true;\n }\n }\n\n return false;\n };\n}\n","/**\n * @file 模块联邦工具\n * @description 提取模块联邦配置中的 exposes 路径\n */\n\nimport type { FederationExposeValue } from '../types';\n\n/**\n * 从 Vite 配置中提取模块联邦暴露的组件路径\n * 支持 @originjs/vite-plugin-federation 和 @module-federation/vite\n * @param config - Vite 解析后的配置\n * @returns JSX/TSX 组件路径列表\n */\nexport function extractExposedPaths(config: any): string[] {\n if (!config?.plugins) return [];\n\n for (const plugin of config.plugins) {\n if (!plugin || typeof plugin !== 'object') continue;\n\n // 方式1:@originjs/vite-plugin-federation(直接 exposes 属性)\n if (plugin.exposes && typeof plugin.exposes === 'object') {\n return extractPathsFromExposes(plugin.exposes);\n }\n\n // 方式2:@module-federation/vite(_options.exposes 属性)\n if (plugin._options?.exposes && typeof plugin._options.exposes === 'object') {\n return extractPathsFromExposes(plugin._options.exposes);\n }\n }\n\n return [];\n}\n\n/**\n * 从 exposes 配置中提取 JSX/TSX 路径\n * @param exposes - exposes 配置对象\n * @returns 路径列表\n */\nfunction extractPathsFromExposes(exposes: Record<string, string | FederationExposeValue>): string[] {\n return Object.values(exposes)\n .map((value) => {\n // 字符串格式:'./src/xxx.jsx'\n if (typeof value === 'string') return value;\n // 对象格式:{ import: './src/xxx.jsx' }\n if (value?.import) return value.import;\n return null;\n })\n .filter((path): path is string => typeof path === 'string' && /\\.(jsx|tsx)$/.test(path));\n}\n","/**\n * @file PostCSS 作用域插件\n * @description 给 CSS 选择器添加作用域前缀\n */\n\n/** 需要跳过的全局选择器前缀 */\nconst GLOBAL_SELECTOR_PREFIXES = [\n ':root',\n 'html',\n 'body',\n 'html ',\n 'body ',\n ':root ',\n 'html.',\n 'body.',\n 'html[',\n 'body['\n];\n\n/** 关键帧选择器正则(0%, 100%, from, to) */\nconst KEYFRAME_SELECTOR_REGEX = /^(\\d+%|from|to)$/;\n\n/**\n * 创建 PostCSS 作用域插件\n * @param scope - 作用域类名\n * @param shouldTransform - 路径匹配函数\n * @returns PostCSS 插件\n */\nexport function createScopePostcssPlugin(scope: string, shouldTransform: (path: string) => boolean) {\n const plugin = (): any => ({\n postcssPlugin: 'css-scope-plugin',\n\n Once(root: any, { result }: any) {\n const filePath = result.opts.from || '';\n\n // 检查文件是否需要处理\n if (!shouldTransform(filePath)) return;\n\n root.walkRules((rule: any) => {\n // 跳过 @keyframes 内部规则\n if (isInsideKeyframes(rule)) return;\n\n // 跳过关键帧选择器\n if (KEYFRAME_SELECTOR_REGEX.test(rule.selector.trim())) return;\n\n // 转换选择器\n rule.selector = transformSelectors(rule.selector, scope);\n });\n }\n });\n\n // 标记为 PostCSS 插件\n (plugin as any).postcss = true;\n\n return plugin;\n}\n\n/**\n * 检查规则是否在 @keyframes 内部\n */\nfunction isInsideKeyframes(rule: any): boolean {\n const parent = rule.parent;\n if (parent?.type !== 'atrule') return false;\n\n const name = parent.name;\n return name === 'keyframes' || name === '-webkit-keyframes' || name === '-moz-keyframes';\n}\n\n/**\n * 转换选择器,添加作用域前缀\n * @param selector - 原始选择器\n * @param scope - 作用域类名\n * @returns 转换后的选择器\n */\nfunction transformSelectors(selector: string, scope: string): string {\n return selector\n .split(',')\n .map((sel) => {\n const trimmed = sel.trim();\n\n // 全局选择器不包裹\n if (isGlobalSelector(trimmed)) return sel;\n\n return `.${scope} ${sel}`;\n })\n .join(', ');\n}\n\n/**\n * 检查是否为全局选择器\n */\nfunction isGlobalSelector(selector: string): boolean {\n return GLOBAL_SELECTOR_PREFIXES.some(\n (prefix) => selector === prefix.trim() || selector.startsWith(prefix)\n );\n}\n","/**\n * @file Babel 转换器\n * @description 转换 JSX/TSX 组件,注入作用域逻辑\n */\n\nimport { parse } from '@babel/parser';\nimport traverseModule from '@babel/traverse';\nimport generateModule from '@babel/generator';\nimport * as t from '@babel/types';\nimport type { NodePath } from '@babel/traverse';\nimport { getComponentFunctionPath } from './hoc-detector';\nimport { injectScopeLogic } from './scope-injector';\n\n// 处理 ES Module 和 CommonJS 的兼容性\nconst traverse = (traverseModule as any).default || traverseModule;\nconst generate = (generateModule as any).default || generateModule;\n\n/**\n * 转换组件代码,注入作用域逻辑\n * @param code - 源代码\n * @param filePath - 文件路径(用于错误提示)\n * @param scope - 作用域类名\n * @returns 转换后的代码\n */\nexport function transformComponent(code: string, filePath: string, scope: string): string {\n try {\n // 解析 AST\n const ast = parse(code, {\n sourceType: 'module',\n plugins: ['jsx', 'typescript']\n });\n\n // 收集需要处理的函数\n const functionsToProcess: NodePath<any>[] = [];\n\n // 遍历 AST,找到所有 export 的组件\n traverse(ast, {\n // export default function Component() {}\n // export default forwardRef(...)\n ExportDefaultDeclaration(path: NodePath<any>) {\n const declaration = path.node.declaration;\n const result = getComponentFunctionPath(path.get('declaration'));\n\n if (result.isValid && result.funcPath) {\n functionsToProcess.push(result.funcPath);\n }\n // export default Component(标识符引用)\n else if (t.isIdentifier(declaration)) {\n const binding = path.scope.getBinding(declaration.name);\n if (binding?.path.isVariableDeclarator()) {\n const initPath = binding.path.get('init');\n const result = getComponentFunctionPath(initPath as NodePath<any>);\n if (result.isValid && result.funcPath) {\n functionsToProcess.push(result.funcPath);\n }\n } else if (binding?.path.isFunctionDeclaration()) {\n functionsToProcess.push(binding.path);\n }\n }\n },\n\n // export const Component = ...\n // export function Component() {}\n ExportNamedDeclaration(path: NodePath<any>) {\n const declaration = path.node.declaration;\n\n if (t.isVariableDeclaration(declaration)) {\n declaration.declarations.forEach((_: any, index: number) => {\n const initPath = path.get(`declaration.declarations.${index}.init`);\n const result = getComponentFunctionPath(initPath as NodePath<any>);\n if (result.isValid && result.funcPath) {\n functionsToProcess.push(result.funcPath);\n }\n });\n } else if (t.isFunctionDeclaration(declaration)) {\n functionsToProcess.push(path.get('declaration'));\n }\n }\n });\n\n // 处理所有收集到的函数\n functionsToProcess.forEach((funcPath) => {\n injectScopeLogic(funcPath, scope);\n });\n\n // 生成代码\n const result = generate(ast, {\n retainLines: false,\n comments: true\n });\n\n return result.code;\n } catch (error) {\n console.error(`[css-scope-plugin] 转换组件失败: ${filePath}`, error);\n return code;\n }\n}\n","/**\n * @file HOC 检测器\n * @description 检测和提取高阶组件(forwardRef、memo)中的真实组件函数\n */\n\nimport * as t from '@babel/types';\nimport type { NodePath } from '@babel/traverse';\nimport type { ComponentFunctionResult } from '../types';\n\n/** 支持的 HOC 名称 */\nconst HOC_NAMES = ['forwardRef', 'memo'];\n\n/**\n * 检查节点是否是 HOC 调用\n * 支持:forwardRef(...)、memo(...)、React.forwardRef(...)、React.memo(...)\n */\nexport function isHOCCall(node: any): boolean {\n if (!t.isCallExpression(node)) return false;\n\n const callee = node.callee;\n\n // 直接调用:forwardRef(...) 或 memo(...)\n if (t.isIdentifier(callee)) {\n return HOC_NAMES.includes(callee.name);\n }\n\n // 成员调用:React.forwardRef(...) 或 React.memo(...)\n if (\n t.isMemberExpression(callee) &&\n t.isIdentifier(callee.object, { name: 'React' }) &&\n t.isIdentifier(callee.property)\n ) {\n return HOC_NAMES.includes(callee.property.name);\n }\n\n return false;\n}\n\n/**\n * 检查节点是否是函数(声明、表达式、箭头函数)\n */\nexport function isFunctionNode(node: any): boolean {\n return (\n t.isFunctionDeclaration(node) ||\n t.isArrowFunctionExpression(node) ||\n t.isFunctionExpression(node)\n );\n}\n\n/**\n * 从 NodePath 中提取组件函数路径\n * 递归处理 HOC 包裹,直到找到真实的函数\n * @param nodePath - AST 节点路径\n * @returns 提取结果\n */\nexport function getComponentFunctionPath(nodePath: NodePath<any>): ComponentFunctionResult {\n const node = nodePath.node;\n\n // 直接是函数 → 返回\n if (isFunctionNode(node)) {\n return { funcPath: nodePath, isValid: true };\n }\n\n // 是 HOC 调用 → 递归提取第一个参数\n if (isHOCCall(node) && node.arguments.length > 0) {\n return getComponentFunctionPath(nodePath.get('arguments.0') as NodePath<any>);\n }\n\n return { funcPath: null, isValid: false };\n}\n","/**\n * @file 作用域注入器\n * @description 向 React 组件注入作用域逻辑(回调 ref + 辅助 div)\n */\n\nimport * as t from '@babel/types';\nimport type { NodePath } from '@babel/traverse';\nimport traverseModule from '@babel/traverse';\n\nconst traverse = (traverseModule as any).default || traverseModule;\n\n/**\n * 检查函数是否是 React 组件(返回 JSX)\n */\nexport function isReactComponent(funcPath: NodePath<any>): boolean {\n let hasJSXReturn = false;\n\n traverse(\n funcPath.node,\n {\n ReturnStatement(returnPath: NodePath<any>) {\n const argument = returnPath.node.argument;\n if (!argument) return;\n\n // 直接返回 JSX\n if (t.isJSXElement(argument) || t.isJSXFragment(argument)) {\n hasJSXReturn = true;\n returnPath.stop();\n return;\n }\n\n // 条件表达式返回 JSX\n if (\n t.isConditionalExpression(argument) &&\n (t.isJSXElement(argument.consequent) || t.isJSXElement(argument.alternate))\n ) {\n hasJSXReturn = true;\n returnPath.stop();\n }\n }\n },\n funcPath.scope,\n funcPath\n );\n\n return hasJSXReturn;\n}\n\n/**\n * 向组件函数注入作用域逻辑\n * @param path - 函数节点路径\n * @param scopeClassName - 作用域类名\n */\nexport function injectScopeLogic(path: NodePath<any>, scopeClassName: string): void {\n const body = path.node.body;\n\n // 确保函数体是 BlockStatement\n if (!t.isBlockStatement(body)) return;\n\n // 只处理 React 组件\n if (!isReactComponent(path)) return;\n\n // 1. 创建回调 ref 声明\n const refCallbackDeclaration = createRefCallbackDeclaration(scopeClassName);\n\n // 2. 在函数体开头注入\n body.body.unshift(refCallbackDeclaration);\n\n // 3. 包裹 return 语句\n wrapReturnStatements(path);\n}\n\n/**\n * 创建回调 ref 函数声明\n * 生成代码:\n * const __scopeRefCallback = (__el) => {\n * if (__el) {\n * const __parent = __el.parentElement;\n * if (__parent) {\n * __parent.classList.add(\"scopeClassName\");\n * __el.remove();\n * }\n * }\n * };\n */\nfunction createRefCallbackDeclaration(scopeClassName: string): t.VariableDeclaration {\n return t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier('__scopeRefCallback'),\n t.arrowFunctionExpression(\n [t.identifier('__el')],\n t.blockStatement([\n // if (__el) { ... }\n t.ifStatement(\n t.identifier('__el'),\n t.blockStatement([\n // const __parent = __el.parentElement;\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier('__parent'),\n t.memberExpression(t.identifier('__el'), t.identifier('parentElement'))\n )\n ]),\n // if (__parent) { ... }\n t.ifStatement(\n t.identifier('__parent'),\n t.blockStatement([\n // __parent.classList.add(\"scopeClassName\");\n t.expressionStatement(\n t.callExpression(\n t.memberExpression(\n t.memberExpression(t.identifier('__parent'), t.identifier('classList')),\n t.identifier('add')\n ),\n [t.stringLiteral(scopeClassName)]\n )\n ),\n // __el.remove();\n t.expressionStatement(\n t.callExpression(t.memberExpression(t.identifier('__el'), t.identifier('remove')), [])\n )\n ])\n )\n ])\n )\n ])\n )\n )\n ]);\n}\n\n/**\n * 包裹 return 语句,添加辅助 div\n */\nfunction wrapReturnStatements(path: NodePath<any>): void {\n traverse(\n path.node,\n {\n ReturnStatement(returnPath: NodePath<any>) {\n // 只处理当前函数的 return,跳过嵌套函数\n if (returnPath.scope !== path.scope) return;\n\n const argument = returnPath.node.argument;\n if (!argument) return;\n\n // 创建辅助 div\n const helperDiv = createHelperDiv();\n\n // 包裹原始返回值\n let wrappedArgument = argument;\n if (!t.isJSXElement(argument) && !t.isJSXFragment(argument)) {\n wrappedArgument = t.jsxExpressionContainer(argument);\n }\n\n // 用 Fragment 包裹\n returnPath.node.argument = t.jsxFragment(\n t.jsxOpeningFragment(),\n t.jsxClosingFragment(),\n [helperDiv, wrappedArgument]\n );\n\n returnPath.stop();\n }\n },\n path.scope,\n path\n );\n}\n\n/**\n * 创建辅助 div 元素\n * 生成代码:<div ref={__scopeRefCallback} style={{width: 0, height: 0, overflow: 'hidden'}}></div>\n */\nfunction createHelperDiv(): t.JSXElement {\n return t.jsxElement(\n t.jsxOpeningElement(\n t.jsxIdentifier('div'),\n [\n // ref={__scopeRefCallback}\n t.jsxAttribute(\n t.jsxIdentifier('ref'),\n t.jsxExpressionContainer(t.identifier('__scopeRefCallback'))\n ),\n // style={{width: 0, height: 0, overflow: 'hidden'}}\n t.jsxAttribute(\n t.jsxIdentifier('style'),\n t.jsxExpressionContainer(\n t.objectExpression([\n t.objectProperty(t.identifier('width'), t.numericLiteral(0)),\n t.objectProperty(t.identifier('height'), t.numericLiteral(0)),\n t.objectProperty(t.identifier('overflow'), t.stringLiteral('hidden'))\n ])\n )\n )\n ],\n true\n ),\n null,\n [],\n true\n );\n}\n","/**\n * @file HTML 转换器\n * @description 给 index.html 的 <body> 标签添加作用域类名\n */\n\n/**\n * 转换 HTML,给 body 添加作用域类名\n * @param html - 原始 HTML\n * @param scope - 作用域类名\n * @returns 转换后的 HTML\n */\nexport function transformHtml(html: string, scope: string): string {\n // 情况1: <body class=\"xxx\"> - 已有 class,追加作用域类名\n if (/<body[^>]*\\sclass\\s*=\\s*[\"']/.test(html)) {\n return html.replace(/(<body[^>]*\\sclass\\s*=\\s*[\"'])([^\"']*)/, `$1${scope} $2`);\n }\n\n // 情况2: <body ...> - 有其他属性但无 class,插入 class 属性\n if (/<body\\s+[^>]*>/.test(html)) {\n return html.replace(/(<body)(\\s+[^>]*>)/, `$1 class=\"${scope}\"$2`);\n }\n\n // 情况3: <body> - 纯净的 body 标签\n return html.replace('<body>', `<body class=\"${scope}\">`);\n}\n","/**\n * @file Vite CSS 作用域隔离插件\n * @description 解决微前端和模块联邦中的样式冲突问题\n *\n * 核心功能:\n * 1. CSS 选择器包裹:.btn → .appProcess .btn\n * 2. JSX 组件注入:自动给模块联邦暴露的组件父元素添加作用域 className\n * 3. HTML 注入:自动给 <body> 添加作用域类名\n *\n * @example\n * ```ts\n * import cssScopePlugin from '@jiayouzuo/vite-plugin-css-scope';\n *\n * export default defineConfig({\n * plugins: [\n * cssScopePlugin({\n * scope: 'appProcess',\n * include: ['src/', 'node_modules/@designable/'],\n * exclude: ['node_modules/antd']\n * })\n * ]\n * });\n * ```\n */\n\nimport type { Plugin } from 'vite';\nimport type { CssScopePluginOptions } from './types';\nimport { createPathMatcher } from './utils/path-matcher';\nimport { extractExposedPaths } from './utils/federation';\nimport { createScopePostcssPlugin } from './postcss/scope-plugin';\nimport { transformComponent } from './babel/transform';\nimport { transformHtml } from './html/transformer';\n\n/**\n * CSS 作用域隔离插件\n * @param options - 插件配置\n * @returns Vite 插件\n */\nexport default function cssScopePlugin(options: CssScopePluginOptions): Plugin {\n const { scope, include, exclude = [] } = options;\n\n // 存储模块联邦暴露的组件路径\n let exposedComponentPaths: string[] = [];\n\n // 验证配置\n if (!scope) {\n throw new Error('[css-scope-plugin] scope 配置不能为空');\n }\n if (!include || include.length === 0) {\n throw new Error('[css-scope-plugin] include 配置不能为空');\n }\n\n // 创建路径匹配器\n const shouldTransform = createPathMatcher(include, exclude);\n\n return {\n name: 'css-scope-plugin',\n enforce: 'pre', // 在 React 插件之前执行\n\n /**\n * 配置解析完成后,提取模块联邦 exposes 路径\n */\n configResolved(resolvedConfig) {\n exposedComponentPaths = extractExposedPaths(resolvedConfig);\n },\n\n /**\n * 注入 PostCSS 插件\n */\n config() {\n return {\n css: {\n postcss: {\n plugins: [createScopePostcssPlugin(scope, shouldTransform)()]\n }\n }\n };\n },\n\n /**\n * 转换模块联邦暴露的 JSX/TSX 组件\n */\n transform(code, id) {\n // 只处理 JSX/TSX 文件\n if (!/\\.(jsx|tsx)$/.test(id)) return null;\n\n // 检查是否是暴露的组件\n const isExposed = exposedComponentPaths.some((exposedPath) => {\n const normalizedPath = exposedPath.replace(/^\\.\\//, '');\n return id.includes(normalizedPath);\n });\n\n if (!isExposed) return null;\n\n // 转换组件\n return {\n code: transformComponent(code, id, scope),\n map: null\n };\n },\n\n /**\n * 给 index.html 的 <body> 添加作用域类名\n */\n transformIndexHtml(html) {\n return transformHtml(html, scope);\n }\n };\n}\n\n// 导出类型\nexport type { CssScopePluginOptions };\n"],"mappings":";AAWO,SAAS,kBAAkB,SAAmB,SAAmB;AAMtE,SAAO,SAAS,gBAAgB,UAA2B;AAEzD,eAAW,WAAW,SAAS;AAC7B,UAAI,SAAS,SAAS,OAAO,GAAG;AAC9B,eAAO;AAAA,MACT;AAAA,IACF;AAGA,eAAW,WAAW,SAAS;AAC7B,UAAI,SAAS,SAAS,OAAO,GAAG;AAC9B,eAAO;AAAA,MACT;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF;;;ACrBO,SAAS,oBAAoB,QAAuB;AAb3D;AAcE,MAAI,EAAC,iCAAQ,SAAS,QAAO,CAAC;AAE9B,aAAW,UAAU,OAAO,SAAS;AACnC,QAAI,CAAC,UAAU,OAAO,WAAW,SAAU;AAG3C,QAAI,OAAO,WAAW,OAAO,OAAO,YAAY,UAAU;AACxD,aAAO,wBAAwB,OAAO,OAAO;AAAA,IAC/C;AAGA,UAAI,YAAO,aAAP,mBAAiB,YAAW,OAAO,OAAO,SAAS,YAAY,UAAU;AAC3E,aAAO,wBAAwB,OAAO,SAAS,OAAO;AAAA,IACxD;AAAA,EACF;AAEA,SAAO,CAAC;AACV;AAOA,SAAS,wBAAwB,SAAmE;AAClG,SAAO,OAAO,OAAO,OAAO,EACzB,IAAI,CAAC,UAAU;AAEd,QAAI,OAAO,UAAU,SAAU,QAAO;AAEtC,QAAI,+BAAO,OAAQ,QAAO,MAAM;AAChC,WAAO;AAAA,EACT,CAAC,EACA,OAAO,CAAC,SAAyB,OAAO,SAAS,YAAY,eAAe,KAAK,IAAI,CAAC;AAC3F;;;AC1CA,IAAM,2BAA2B;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGA,IAAM,0BAA0B;AAQzB,SAAS,yBAAyB,OAAe,iBAA4C;AAClG,QAAM,SAAS,OAAY;AAAA,IACzB,eAAe;AAAA,IAEf,KAAK,MAAW,EAAE,OAAO,GAAQ;AAC/B,YAAM,WAAW,OAAO,KAAK,QAAQ;AAGrC,UAAI,CAAC,gBAAgB,QAAQ,EAAG;AAEhC,WAAK,UAAU,CAAC,SAAc;AAE5B,YAAI,kBAAkB,IAAI,EAAG;AAG7B,YAAI,wBAAwB,KAAK,KAAK,SAAS,KAAK,CAAC,EAAG;AAGxD,aAAK,WAAW,mBAAmB,KAAK,UAAU,KAAK;AAAA,MACzD,CAAC;AAAA,IACH;AAAA,EACF;AAGA,EAAC,OAAe,UAAU;AAE1B,SAAO;AACT;AAKA,SAAS,kBAAkB,MAAoB;AAC7C,QAAM,SAAS,KAAK;AACpB,OAAI,iCAAQ,UAAS,SAAU,QAAO;AAEtC,QAAM,OAAO,OAAO;AACpB,SAAO,SAAS,eAAe,SAAS,uBAAuB,SAAS;AAC1E;AAQA,SAAS,mBAAmB,UAAkB,OAAuB;AACnE,SAAO,SACJ,MAAM,GAAG,EACT,IAAI,CAAC,QAAQ;AACZ,UAAM,UAAU,IAAI,KAAK;AAGzB,QAAI,iBAAiB,OAAO,EAAG,QAAO;AAEtC,WAAO,IAAI,KAAK,IAAI,GAAG;AAAA,EACzB,CAAC,EACA,KAAK,IAAI;AACd;AAKA,SAAS,iBAAiB,UAA2B;AACnD,SAAO,yBAAyB;AAAA,IAC9B,CAAC,WAAW,aAAa,OAAO,KAAK,KAAK,SAAS,WAAW,MAAM;AAAA,EACtE;AACF;;;AC1FA,SAAS,aAAa;AACtB,OAAOA,qBAAoB;AAC3B,OAAO,oBAAoB;AAC3B,YAAYC,QAAO;;;ACHnB,YAAY,OAAO;AAKnB,IAAM,YAAY,CAAC,cAAc,MAAM;AAMhC,SAAS,UAAU,MAAoB;AAC5C,MAAI,CAAG,mBAAiB,IAAI,EAAG,QAAO;AAEtC,QAAM,SAAS,KAAK;AAGpB,MAAM,eAAa,MAAM,GAAG;AAC1B,WAAO,UAAU,SAAS,OAAO,IAAI;AAAA,EACvC;AAGA,MACI,qBAAmB,MAAM,KACzB,eAAa,OAAO,QAAQ,EAAE,MAAM,QAAQ,CAAC,KAC7C,eAAa,OAAO,QAAQ,GAC9B;AACA,WAAO,UAAU,SAAS,OAAO,SAAS,IAAI;AAAA,EAChD;AAEA,SAAO;AACT;AAKO,SAAS,eAAe,MAAoB;AACjD,SACI,wBAAsB,IAAI,KAC1B,4BAA0B,IAAI,KAC9B,uBAAqB,IAAI;AAE/B;AAQO,SAAS,yBAAyB,UAAkD;AACzF,QAAM,OAAO,SAAS;AAGtB,MAAI,eAAe,IAAI,GAAG;AACxB,WAAO,EAAE,UAAU,UAAU,SAAS,KAAK;AAAA,EAC7C;AAGA,MAAI,UAAU,IAAI,KAAK,KAAK,UAAU,SAAS,GAAG;AAChD,WAAO,yBAAyB,SAAS,IAAI,aAAa,CAAkB;AAAA,EAC9E;AAEA,SAAO,EAAE,UAAU,MAAM,SAAS,MAAM;AAC1C;;;AChEA,YAAYC,QAAO;AAEnB,OAAO,oBAAoB;AAE3B,IAAM,WAAY,eAAuB,WAAW;AAK7C,SAAS,iBAAiB,UAAkC;AACjE,MAAI,eAAe;AAEnB;AAAA,IACE,SAAS;AAAA,IACT;AAAA,MACE,gBAAgB,YAA2B;AACzC,cAAM,WAAW,WAAW,KAAK;AACjC,YAAI,CAAC,SAAU;AAGf,YAAM,gBAAa,QAAQ,KAAO,iBAAc,QAAQ,GAAG;AACzD,yBAAe;AACf,qBAAW,KAAK;AAChB;AAAA,QACF;AAGA,YACI,2BAAwB,QAAQ,MAC/B,gBAAa,SAAS,UAAU,KAAO,gBAAa,SAAS,SAAS,IACzE;AACA,yBAAe;AACf,qBAAW,KAAK;AAAA,QAClB;AAAA,MACF;AAAA,IACF;AAAA,IACA,SAAS;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;AAOO,SAAS,iBAAiB,MAAqB,gBAA8B;AAClF,QAAM,OAAO,KAAK,KAAK;AAGvB,MAAI,CAAG,oBAAiB,IAAI,EAAG;AAG/B,MAAI,CAAC,iBAAiB,IAAI,EAAG;AAG7B,QAAM,yBAAyB,6BAA6B,cAAc;AAG1E,OAAK,KAAK,QAAQ,sBAAsB;AAGxC,uBAAqB,IAAI;AAC3B;AAeA,SAAS,6BAA6B,gBAA+C;AACnF,SAAS,uBAAoB,SAAS;AAAA,IAClC;AAAA,MACE,cAAW,oBAAoB;AAAA,MAC/B;AAAA,QACA,CAAG,cAAW,MAAM,CAAC;AAAA,QACnB,kBAAe;AAAA;AAAA,UAEb;AAAA,YACE,cAAW,MAAM;AAAA,YACjB,kBAAe;AAAA;AAAA,cAEb,uBAAoB,SAAS;AAAA,gBAC3B;AAAA,kBACE,cAAW,UAAU;AAAA,kBACrB,oBAAmB,cAAW,MAAM,GAAK,cAAW,eAAe,CAAC;AAAA,gBACxE;AAAA,cACF,CAAC;AAAA;AAAA,cAEC;AAAA,gBACE,cAAW,UAAU;AAAA,gBACrB,kBAAe;AAAA;AAAA,kBAEb;AAAA,oBACE;AAAA,sBACE;AAAA,wBACE,oBAAmB,cAAW,UAAU,GAAK,cAAW,WAAW,CAAC;AAAA,wBACpE,cAAW,KAAK;AAAA,sBACpB;AAAA,sBACA,CAAG,iBAAc,cAAc,CAAC;AAAA,oBAClC;AAAA,kBACF;AAAA;AAAA,kBAEE;AAAA,oBACE,kBAAiB,oBAAmB,cAAW,MAAM,GAAK,cAAW,QAAQ,CAAC,GAAG,CAAC,CAAC;AAAA,kBACvF;AAAA,gBACF,CAAC;AAAA,cACH;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAKA,SAAS,qBAAqB,MAA2B;AACvD;AAAA,IACE,KAAK;AAAA,IACL;AAAA,MACE,gBAAgB,YAA2B;AAEzC,YAAI,WAAW,UAAU,KAAK,MAAO;AAErC,cAAM,WAAW,WAAW,KAAK;AACjC,YAAI,CAAC,SAAU;AAGf,cAAM,YAAY,gBAAgB;AAGlC,YAAI,kBAAkB;AACtB,YAAI,CAAG,gBAAa,QAAQ,KAAK,CAAG,iBAAc,QAAQ,GAAG;AAC3D,4BAAoB,0BAAuB,QAAQ;AAAA,QACrD;AAGA,mBAAW,KAAK,WAAa;AAAA,UACzB,sBAAmB;AAAA,UACnB,sBAAmB;AAAA,UACrB,CAAC,WAAW,eAAe;AAAA,QAC7B;AAEA,mBAAW,KAAK;AAAA,MAClB;AAAA,IACF;AAAA,IACA,KAAK;AAAA,IACL;AAAA,EACF;AACF;AAMA,SAAS,kBAAgC;AACvC,SAAS;AAAA,IACL;AAAA,MACE,iBAAc,KAAK;AAAA,MACrB;AAAA;AAAA,QAEI;AAAA,UACE,iBAAc,KAAK;AAAA,UACnB,0BAAyB,cAAW,oBAAoB,CAAC;AAAA,QAC7D;AAAA;AAAA,QAEE;AAAA,UACE,iBAAc,OAAO;AAAA,UACrB;AAAA,YACE,oBAAiB;AAAA,cACf,kBAAiB,cAAW,OAAO,GAAK,kBAAe,CAAC,CAAC;AAAA,cACzD,kBAAiB,cAAW,QAAQ,GAAK,kBAAe,CAAC,CAAC;AAAA,cAC1D,kBAAiB,cAAW,UAAU,GAAK,iBAAc,QAAQ,CAAC;AAAA,YACtE,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,IACA;AAAA,IACA,CAAC;AAAA,IACD;AAAA,EACF;AACF;;;AF3LA,IAAMC,YAAYC,gBAAuB,WAAWA;AACpD,IAAM,WAAY,eAAuB,WAAW;AAS7C,SAAS,mBAAmB,MAAc,UAAkB,OAAuB;AACxF,MAAI;AAEF,UAAM,MAAM,MAAM,MAAM;AAAA,MACtB,YAAY;AAAA,MACZ,SAAS,CAAC,OAAO,YAAY;AAAA,IAC/B,CAAC;AAGD,UAAM,qBAAsC,CAAC;AAG7C,IAAAD,UAAS,KAAK;AAAA;AAAA;AAAA,MAGZ,yBAAyB,MAAqB;AAC5C,cAAM,cAAc,KAAK,KAAK;AAC9B,cAAME,UAAS,yBAAyB,KAAK,IAAI,aAAa,CAAC;AAE/D,YAAIA,QAAO,WAAWA,QAAO,UAAU;AACrC,6BAAmB,KAAKA,QAAO,QAAQ;AAAA,QACzC,WAEW,gBAAa,WAAW,GAAG;AACpC,gBAAM,UAAU,KAAK,MAAM,WAAW,YAAY,IAAI;AACtD,cAAI,mCAAS,KAAK,wBAAwB;AACxC,kBAAM,WAAW,QAAQ,KAAK,IAAI,MAAM;AACxC,kBAAMA,UAAS,yBAAyB,QAAyB;AACjE,gBAAIA,QAAO,WAAWA,QAAO,UAAU;AACrC,iCAAmB,KAAKA,QAAO,QAAQ;AAAA,YACzC;AAAA,UACF,WAAW,mCAAS,KAAK,yBAAyB;AAChD,+BAAmB,KAAK,QAAQ,IAAI;AAAA,UACtC;AAAA,QACF;AAAA,MACF;AAAA;AAAA;AAAA,MAIA,uBAAuB,MAAqB;AAC1C,cAAM,cAAc,KAAK,KAAK;AAE9B,YAAM,yBAAsB,WAAW,GAAG;AACxC,sBAAY,aAAa,QAAQ,CAAC,GAAQ,UAAkB;AAC1D,kBAAM,WAAW,KAAK,IAAI,4BAA4B,KAAK,OAAO;AAClE,kBAAMA,UAAS,yBAAyB,QAAyB;AACjE,gBAAIA,QAAO,WAAWA,QAAO,UAAU;AACrC,iCAAmB,KAAKA,QAAO,QAAQ;AAAA,YACzC;AAAA,UACF,CAAC;AAAA,QACH,WAAa,yBAAsB,WAAW,GAAG;AAC/C,6BAAmB,KAAK,KAAK,IAAI,aAAa,CAAC;AAAA,QACjD;AAAA,MACF;AAAA,IACF,CAAC;AAGD,uBAAmB,QAAQ,CAAC,aAAa;AACvC,uBAAiB,UAAU,KAAK;AAAA,IAClC,CAAC;AAGD,UAAM,SAAS,SAAS,KAAK;AAAA,MAC3B,aAAa;AAAA,MACb,UAAU;AAAA,IACZ,CAAC;AAED,WAAO,OAAO;AAAA,EAChB,SAAS,OAAO;AACd,YAAQ,MAAM,4DAA8B,QAAQ,IAAI,KAAK;AAC7D,WAAO;AAAA,EACT;AACF;;;AGrFO,SAAS,cAAc,MAAc,OAAuB;AAEjE,MAAI,+BAA+B,KAAK,IAAI,GAAG;AAC7C,WAAO,KAAK,QAAQ,0CAA0C,KAAK,KAAK,KAAK;AAAA,EAC/E;AAGA,MAAI,iBAAiB,KAAK,IAAI,GAAG;AAC/B,WAAO,KAAK,QAAQ,sBAAsB,aAAa,KAAK,KAAK;AAAA,EACnE;AAGA,SAAO,KAAK,QAAQ,UAAU,gBAAgB,KAAK,IAAI;AACzD;;;ACce,SAAR,eAAgC,SAAwC;AAC7E,QAAM,EAAE,OAAO,SAAS,UAAU,CAAC,EAAE,IAAI;AAGzC,MAAI,wBAAkC,CAAC;AAGvC,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,+DAAiC;AAAA,EACnD;AACA,MAAI,CAAC,WAAW,QAAQ,WAAW,GAAG;AACpC,UAAM,IAAI,MAAM,iEAAmC;AAAA,EACrD;AAGA,QAAM,kBAAkB,kBAAkB,SAAS,OAAO;AAE1D,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA,IAKT,eAAe,gBAAgB;AAC7B,8BAAwB,oBAAoB,cAAc;AAAA,IAC5D;AAAA;AAAA;AAAA;AAAA,IAKA,SAAS;AACP,aAAO;AAAA,QACL,KAAK;AAAA,UACH,SAAS;AAAA,YACP,SAAS,CAAC,yBAAyB,OAAO,eAAe,EAAE,CAAC;AAAA,UAC9D;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA;AAAA;AAAA;AAAA,IAKA,UAAU,MAAM,IAAI;AAElB,UAAI,CAAC,eAAe,KAAK,EAAE,EAAG,QAAO;AAGrC,YAAM,YAAY,sBAAsB,KAAK,CAAC,gBAAgB;AAC5D,cAAM,iBAAiB,YAAY,QAAQ,SAAS,EAAE;AACtD,eAAO,GAAG,SAAS,cAAc;AAAA,MACnC,CAAC;AAED,UAAI,CAAC,UAAW,QAAO;AAGvB,aAAO;AAAA,QACL,MAAM,mBAAmB,MAAM,IAAI,KAAK;AAAA,QACxC,KAAK;AAAA,MACP;AAAA,IACF;AAAA;AAAA;AAAA;AAAA,IAKA,mBAAmB,MAAM;AACvB,aAAO,cAAc,MAAM,KAAK;AAAA,IAClC;AAAA,EACF;AACF;","names":["traverseModule","t","t","traverse","traverseModule","result"]}
|
|
1
|
+
{"version":3,"sources":["../src/utils/path-matcher.ts","../src/utils/federation.ts","../src/postcss/scope-plugin.ts","../src/babel/transform.ts","../src/babel/hoc-detector.ts","../src/babel/scope-injector.ts","../src/html/transformer.ts","../src/babel/portal-transform.ts","../src/index.ts"],"sourcesContent":["/**\n * @file 路径匹配工具\n * @description 判断文件路径是否需要处理\n */\n\n/**\n * 创建路径匹配器\n * @param include - 包含的路径模式\n * @param exclude - 排除的路径模式\n * @returns 匹配函数\n */\nexport function createPathMatcher(include: string[], exclude: string[]) {\n /**\n * 检查文件是否需要处理\n * @param filePath - 文件路径\n * @returns 是否需要处理\n */\n return function shouldTransform(filePath: string): boolean {\n // 优先检查排除列表\n for (const pattern of exclude) {\n if (filePath.includes(pattern)) {\n return false;\n }\n }\n\n // 检查包含列表\n for (const pattern of include) {\n if (filePath.includes(pattern)) {\n return true;\n }\n }\n\n return false;\n };\n}\n","/**\n * @file 模块联邦工具\n * @description 提取模块联邦配置中的 exposes 路径\n */\n\nimport type { FederationExposeValue } from '../types';\n\n/**\n * 从 Vite 配置中提取模块联邦暴露的组件路径\n * 支持 @originjs/vite-plugin-federation 和 @module-federation/vite\n * @param config - Vite 解析后的配置\n * @returns JSX/TSX 组件路径列表\n */\nexport function extractExposedPaths(config: any): string[] {\n if (!config?.plugins) return [];\n\n for (const plugin of config.plugins) {\n if (!plugin || typeof plugin !== 'object') continue;\n\n // 方式1:@originjs/vite-plugin-federation(直接 exposes 属性)\n if (plugin.exposes && typeof plugin.exposes === 'object') {\n return extractPathsFromExposes(plugin.exposes);\n }\n\n // 方式2:@module-federation/vite(_options.exposes 属性)\n if (plugin._options?.exposes && typeof plugin._options.exposes === 'object') {\n return extractPathsFromExposes(plugin._options.exposes);\n }\n }\n\n return [];\n}\n\n/**\n * 从 exposes 配置中提取 JSX/TSX 路径\n * @param exposes - exposes 配置对象\n * @returns 路径列表\n */\nfunction extractPathsFromExposes(exposes: Record<string, string | FederationExposeValue>): string[] {\n return Object.values(exposes)\n .map((value) => {\n // 字符串格式:'./src/xxx.jsx'\n if (typeof value === 'string') return value;\n // 对象格式:{ import: './src/xxx.jsx' }\n if (value?.import) return value.import;\n return null;\n })\n .filter((path): path is string => typeof path === 'string' && /\\.(jsx|tsx)$/.test(path));\n}\n","/**\n * @file PostCSS 作用域插件\n * @description 给 CSS 选择器添加作用域前缀\n */\n\n/** 需要跳过的全局选择器前缀 */\nconst GLOBAL_SELECTOR_PREFIXES = [\n ':root',\n 'html',\n 'body',\n 'html ',\n 'body ',\n ':root ',\n 'html.',\n 'body.',\n 'html[',\n 'body['\n];\n\n/** 关键帧选择器正则(0%, 100%, from, to) */\nconst KEYFRAME_SELECTOR_REGEX = /^(\\d+%|from|to)$/;\n\n/**\n * 创建 PostCSS 作用域插件\n * @param scope - 作用域类名\n * @param shouldTransform - 路径匹配函数\n * @returns PostCSS 插件\n */\nexport function createScopePostcssPlugin(scope: string, shouldTransform: (path: string) => boolean) {\n const plugin = (): any => ({\n postcssPlugin: 'css-scope-plugin',\n\n Once(root: any, { result }: any) {\n const filePath = result.opts.from || '';\n\n // 检查文件是否需要处理\n if (!shouldTransform(filePath)) return;\n\n root.walkRules((rule: any) => {\n // 跳过 @keyframes 内部规则\n if (isInsideKeyframes(rule)) return;\n\n // 跳过关键帧选择器\n if (KEYFRAME_SELECTOR_REGEX.test(rule.selector.trim())) return;\n\n // 转换选择器\n rule.selector = transformSelectors(rule.selector, scope);\n });\n }\n });\n\n // 标记为 PostCSS 插件\n (plugin as any).postcss = true;\n\n return plugin;\n}\n\n/**\n * 检查规则是否在 @keyframes 内部\n */\nfunction isInsideKeyframes(rule: any): boolean {\n const parent = rule.parent;\n if (parent?.type !== 'atrule') return false;\n\n const name = parent.name;\n return name === 'keyframes' || name === '-webkit-keyframes' || name === '-moz-keyframes';\n}\n\n/**\n * 转换选择器,添加作用域前缀\n * @param selector - 原始选择器\n * @param scope - 作用域类名\n * @returns 转换后的选择器\n */\nfunction transformSelectors(selector: string, scope: string): string {\n return selector\n .split(',')\n .map((sel) => {\n const trimmed = sel.trim();\n\n // 全局选择器不包裹\n if (isGlobalSelector(trimmed)) return sel;\n\n return `[data-scope-${scope}=\"1\"] ${sel}`;\n })\n .join(', ');\n}\n\n/**\n * 检查是否为全局选择器\n */\nfunction isGlobalSelector(selector: string): boolean {\n return GLOBAL_SELECTOR_PREFIXES.some(\n (prefix) => selector === prefix.trim() || selector.startsWith(prefix)\n );\n}\n","/**\n * @file Babel 转换器\n * @description 转换 JSX/TSX 组件,注入作用域逻辑\n */\n\nimport { parse } from '@babel/parser';\nimport traverseModule from '@babel/traverse';\nimport generateModule from '@babel/generator';\nimport * as t from '@babel/types';\nimport type { NodePath } from '@babel/traverse';\nimport { getComponentFunctionPath } from './hoc-detector';\nimport { injectScopeLogic } from './scope-injector';\n\n// 处理 ES Module 和 CommonJS 的兼容性\nconst traverse = (traverseModule as any).default || traverseModule;\nconst generate = (generateModule as any).default || generateModule;\n\n/**\n * 转换组件代码,注入作用域逻辑\n * @param code - 源代码\n * @param filePath - 文件路径(用于错误提示)\n * @param scope - 作用域类名\n * @returns 转换后的代码\n */\nexport function transformComponent(code: string, filePath: string, scope: string): string {\n try {\n // 解析 AST\n const ast = parse(code, {\n sourceType: 'module',\n plugins: ['jsx', 'typescript']\n });\n\n // 收集需要处理的函数\n const functionsToProcess: NodePath<any>[] = [];\n\n // 遍历 AST,找到所有 export 的组件\n traverse(ast, {\n // export default function Component() {}\n // export default forwardRef(...)\n ExportDefaultDeclaration(path: NodePath<any>) {\n const declaration = path.node.declaration;\n const result = getComponentFunctionPath(path.get('declaration'));\n\n if (result.isValid && result.funcPath) {\n functionsToProcess.push(result.funcPath);\n }\n // export default Component(标识符引用)\n else if (t.isIdentifier(declaration)) {\n const binding = path.scope.getBinding(declaration.name);\n if (binding?.path.isVariableDeclarator()) {\n const initPath = binding.path.get('init');\n const result = getComponentFunctionPath(initPath as NodePath<any>);\n if (result.isValid && result.funcPath) {\n functionsToProcess.push(result.funcPath);\n }\n } else if (binding?.path.isFunctionDeclaration()) {\n functionsToProcess.push(binding.path);\n }\n }\n },\n\n // export const Component = ...\n // export function Component() {}\n ExportNamedDeclaration(path: NodePath<any>) {\n const declaration = path.node.declaration;\n\n if (t.isVariableDeclaration(declaration)) {\n declaration.declarations.forEach((_: any, index: number) => {\n const initPath = path.get(`declaration.declarations.${index}.init`);\n const result = getComponentFunctionPath(initPath as NodePath<any>);\n if (result.isValid && result.funcPath) {\n functionsToProcess.push(result.funcPath);\n }\n });\n } else if (t.isFunctionDeclaration(declaration)) {\n functionsToProcess.push(path.get('declaration'));\n }\n }\n });\n\n // 处理所有收集到的函数\n functionsToProcess.forEach((funcPath) => {\n injectScopeLogic(funcPath, scope);\n });\n\n // 生成代码\n const result = generate(ast, {\n retainLines: false,\n comments: true\n });\n\n return result.code;\n } catch (error) {\n console.error(`[css-scope-plugin] 转换组件失败: ${filePath}`, error);\n return code;\n }\n}\n","/**\n * @file HOC 检测器\n * @description 检测和提取高阶组件(forwardRef、memo)中的真实组件函数\n */\n\nimport * as t from '@babel/types';\nimport type { NodePath } from '@babel/traverse';\nimport type { ComponentFunctionResult } from '../types';\n\n/** 支持的 HOC 名称 */\nconst HOC_NAMES = ['forwardRef', 'memo'];\n\n/**\n * 检查节点是否是 HOC 调用\n * 支持:forwardRef(...)、memo(...)、React.forwardRef(...)、React.memo(...)\n */\nexport function isHOCCall(node: any): boolean {\n if (!t.isCallExpression(node)) return false;\n\n const callee = node.callee;\n\n // 直接调用:forwardRef(...) 或 memo(...)\n if (t.isIdentifier(callee)) {\n return HOC_NAMES.includes(callee.name);\n }\n\n // 成员调用:React.forwardRef(...) 或 React.memo(...)\n if (\n t.isMemberExpression(callee) &&\n t.isIdentifier(callee.object, { name: 'React' }) &&\n t.isIdentifier(callee.property)\n ) {\n return HOC_NAMES.includes(callee.property.name);\n }\n\n return false;\n}\n\n/**\n * 检查节点是否是函数(声明、表达式、箭头函数)\n */\nexport function isFunctionNode(node: any): boolean {\n return (\n t.isFunctionDeclaration(node) ||\n t.isArrowFunctionExpression(node) ||\n t.isFunctionExpression(node)\n );\n}\n\n/**\n * 从 NodePath 中提取组件函数路径\n * 递归处理 HOC 包裹,直到找到真实的函数\n * @param nodePath - AST 节点路径\n * @returns 提取结果\n */\nexport function getComponentFunctionPath(nodePath: NodePath<any>): ComponentFunctionResult {\n const node = nodePath.node;\n\n // 直接是函数 → 返回\n if (isFunctionNode(node)) {\n return { funcPath: nodePath, isValid: true };\n }\n\n // 是 HOC 调用 → 递归提取第一个参数\n if (isHOCCall(node) && node.arguments.length > 0) {\n return getComponentFunctionPath(nodePath.get('arguments.0') as NodePath<any>);\n }\n\n return { funcPath: null, isValid: false };\n}\n","/**\n * @file 作用域注入器\n * @description 向 React 组件注入作用域逻辑(回调 ref + 辅助 div)\n */\n\nimport * as t from '@babel/types';\nimport type { NodePath } from '@babel/traverse';\nimport traverseModule from '@babel/traverse';\n\nconst traverse = (traverseModule as any).default || traverseModule;\n\n/**\n * 检查函数是否是 React 组件(返回 JSX)\n */\nexport function isReactComponent(funcPath: NodePath<any>): boolean {\n let hasJSXReturn = false;\n\n traverse(\n funcPath.node,\n {\n ReturnStatement(returnPath: NodePath<any>) {\n const argument = returnPath.node.argument;\n if (!argument) return;\n\n // 直接返回 JSX\n if (t.isJSXElement(argument) || t.isJSXFragment(argument)) {\n hasJSXReturn = true;\n returnPath.stop();\n return;\n }\n\n // 条件表达式返回 JSX\n if (\n t.isConditionalExpression(argument) &&\n (t.isJSXElement(argument.consequent) || t.isJSXElement(argument.alternate))\n ) {\n hasJSXReturn = true;\n returnPath.stop();\n }\n }\n },\n funcPath.scope,\n funcPath\n );\n\n return hasJSXReturn;\n}\n\n/**\n * 向组件函数注入作用域逻辑\n * @param path - 函数节点路径\n * @param scopeClassName - 作用域类名\n */\nexport function injectScopeLogic(path: NodePath<any>, scopeClassName: string): void {\n const body = path.node.body;\n\n // 确保函数体是 BlockStatement\n if (!t.isBlockStatement(body)) return;\n\n // 只处理 React 组件\n if (!isReactComponent(path)) return;\n\n // 1. 创建回调 ref 声明\n const refCallbackDeclaration = createRefCallbackDeclaration(scopeClassName);\n\n // 2. 在函数体开头注入\n body.body.unshift(refCallbackDeclaration);\n\n // 3. 包裹 return 语句\n wrapReturnStatements(path);\n}\n\n/**\n * 创建回调 ref 函数声明\n * 生成代码:\n * const __scopeRefCallback = (__el) => {\n * if (__el) {\n * const __parent = __el.parentElement;\n * if (__parent && !__parent.hasAttribute(\"data-scope-xxx\")) {\n * __parent.setAttribute(\"data-scope-xxx\", \"1\");\n * }\n * }\n * };\n */\nfunction createRefCallbackDeclaration(scopeClassName: string): t.VariableDeclaration {\n const attrName = `data-scope-${scopeClassName}`;\n return t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier('__scopeRefCallback'),\n t.arrowFunctionExpression(\n [t.identifier('__el')],\n t.blockStatement([\n // if (__el) { ... }\n t.ifStatement(\n t.identifier('__el'),\n t.blockStatement([\n // const __parent = __el.parentElement;\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier('__parent'),\n t.memberExpression(t.identifier('__el'), t.identifier('parentElement'))\n )\n ]),\n // if (__parent && !__parent.hasAttribute(\"data-scope-xxx\")) { ... }\n t.ifStatement(\n t.logicalExpression(\n '&&',\n t.identifier('__parent'),\n t.unaryExpression(\n '!',\n t.callExpression(\n t.memberExpression(t.identifier('__parent'), t.identifier('hasAttribute')),\n [t.stringLiteral(attrName)]\n )\n )\n ),\n t.blockStatement([\n // __parent.setAttribute(\"data-scope-xxx\", \"1\");\n t.expressionStatement(\n t.callExpression(\n t.memberExpression(t.identifier('__parent'), t.identifier('setAttribute')),\n [t.stringLiteral(attrName), t.stringLiteral('1')]\n )\n )\n ])\n )\n ])\n )\n ])\n )\n )\n ]);\n}\n\n/**\n * 包裹 return 语句,添加辅助 div\n */\nfunction wrapReturnStatements(path: NodePath<any>): void {\n traverse(\n path.node,\n {\n ReturnStatement(returnPath: NodePath<any>) {\n // 只处理当前函数的 return,跳过嵌套函数\n if (returnPath.scope !== path.scope) return;\n\n const argument = returnPath.node.argument;\n if (!argument) return;\n\n // 创建辅助 div\n const helperDiv = createHelperDiv();\n\n // 包裹原始返回值\n let wrappedArgument = argument;\n if (!t.isJSXElement(argument) && !t.isJSXFragment(argument)) {\n wrappedArgument = t.jsxExpressionContainer(argument);\n }\n\n // 用 Fragment 包裹\n returnPath.node.argument = t.jsxFragment(\n t.jsxOpeningFragment(),\n t.jsxClosingFragment(),\n [helperDiv, wrappedArgument]\n );\n\n returnPath.stop();\n }\n },\n path.scope,\n path\n );\n}\n\n/**\n * 创建辅助 div 元素\n * 生成代码:<div ref={__scopeRefCallback} style={{width: 0, height: 0, overflow: 'hidden'}}></div>\n */\nfunction createHelperDiv(): t.JSXElement {\n return t.jsxElement(\n t.jsxOpeningElement(\n t.jsxIdentifier('div'),\n [\n // ref={__scopeRefCallback}\n t.jsxAttribute(\n t.jsxIdentifier('ref'),\n t.jsxExpressionContainer(t.identifier('__scopeRefCallback'))\n ),\n // style={{width: 0, height: 0, overflow: 'hidden'}}\n t.jsxAttribute(\n t.jsxIdentifier('style'),\n t.jsxExpressionContainer(\n t.objectExpression([\n t.objectProperty(t.identifier('width'), t.numericLiteral(0)),\n t.objectProperty(t.identifier('height'), t.numericLiteral(0)),\n t.objectProperty(t.identifier('overflow'), t.stringLiteral('hidden'))\n ])\n )\n )\n ],\n true\n ),\n null,\n [],\n true\n );\n}\n","/**\n * @file HTML 转换器\n * @description 给 index.html 的 <body> 标签添加作用域属性\n */\n\n/**\n * 转换 HTML,给 body 添加作用域属性\n * @param html - 原始 HTML\n * @param scope - 作用域名称\n * @returns 转换后的 HTML\n */\nexport function transformHtml(html: string, scope: string): string {\n const attrName = `data-scope-${scope}`;\n\n // 情况1: <body ...> - 有属性,在属性后追加\n if (/<body\\s+[^>]*>/.test(html)) {\n return html.replace(/(<body)(\\s+[^>]*>)/, `$1 ${attrName}=\"1\"$2`);\n }\n\n // 情况2: <body> - 纯净的 body 标签\n return html.replace('<body>', `<body ${attrName}=\"1\">`);\n}\n","/**\n * @file Portal 容器转换器\n * @description 给 antd 全局挂载组件的容器注入作用域类名\n *\n * 处理的文件:\n * 1. @rc-component/portal/es/useDom.js → Modal, Drawer\n * 2. rc-trigger/es/index.js → Dropdown, Select, Tooltip, Popover 等\n * 3. rc-notification/es/Notification.js → Message, Notification\n */\n\nimport { parse } from '@babel/parser';\nimport traverseModule from '@babel/traverse';\nimport generateModule from '@babel/generator';\nimport * as t from '@babel/types';\n\nconst traverse = (traverseModule as any).default || traverseModule;\nconst generate = (generateModule as any).default || generateModule;\n\n/**\n * Portal 文件匹配规则\n */\nconst PORTAL_FILES = [\n // @rc-component/portal/es/useDom.js - Modal, Drawer\n { pattern: /@rc-component[\\/\\\\]portal[\\/\\\\].*useDom/, varName: 'defaultEle' },\n // rc-trigger/es/index.js - Dropdown, Select, Tooltip 等\n { pattern: /rc-trigger[\\/\\\\].*index\\.js/, varName: 'popupContainer' },\n // rc-notification/es/Notification.js - Message, Notification\n { pattern: /rc-notification[\\/\\\\].*Notification\\.js/, varName: 'div' },\n];\n\n/**\n * 检查文件是否是 portal 相关文件\n */\nexport function isPortalFile(id: string): { match: boolean; varName?: string } {\n for (const { pattern, varName } of PORTAL_FILES) {\n if (pattern.test(id)) {\n return { match: true, varName };\n }\n }\n return { match: false };\n}\n\n/**\n * 转换 portal 文件,注入作用域类名\n */\nexport function transformPortal(code: string, id: string, scope: string, targetVarName: string): string | null {\n try {\n const ast = parse(code, {\n sourceType: 'module',\n plugins: ['jsx']\n });\n\n let modified = false;\n\n traverse(ast, {\n VariableDeclarator(path: any) {\n // 匹配: var xxx = yyy.createElement('div')\n const init = path.node.init;\n if (\n t.isIdentifier(path.node.id) &&\n path.node.id.name === targetVarName &&\n t.isCallExpression(init) &&\n t.isMemberExpression(init.callee) &&\n t.isIdentifier(init.callee.property, { name: 'createElement' }) &&\n init.arguments.length > 0 &&\n t.isStringLiteral(init.arguments[0], { value: 'div' })\n ) {\n const parentDecl = path.parentPath;\n if (t.isVariableDeclaration(parentDecl.node)) {\n // 插入: varName.setAttribute('data-scope-xxx', '1')\n const attrName = `data-scope-${scope}`;\n parentDecl.insertAfter(\n t.expressionStatement(\n t.callExpression(\n t.memberExpression(t.identifier(targetVarName), t.identifier('setAttribute')),\n [t.stringLiteral(attrName), t.stringLiteral('1')]\n )\n )\n );\n modified = true;\n console.log(`[css-scope-plugin] 注入 portal 作用域: ${id.split(/[\\/\\\\]/).pop()} -> ${targetVarName}.setAttribute(\"${attrName}\", \"1\")`);\n }\n }\n }\n });\n\n if (modified) {\n const result = generate(ast, { retainLines: true, comments: true });\n return result.code;\n }\n\n return null;\n } catch (error: any) {\n console.error(`[css-scope-plugin] portal 转换失败: ${id}`, error.message);\n return null;\n }\n}\n","/**\n * @file Vite CSS 作用域隔离插件\n * @description 解决微前端和模块联邦中的样式冲突问题\n *\n * 核心功能:\n * 1. CSS 选择器包裹:.btn → .appProcess .btn\n * 2. JSX 组件注入:自动给模块联邦暴露的组件父元素添加作用域 className\n * 3. HTML 注入:自动给 <body> 添加作用域类名\n *\n * @example\n * ```ts\n * import cssScopePlugin from '@jiayouzuo/vite-plugin-css-scope';\n *\n * export default defineConfig({\n * plugins: [\n * cssScopePlugin({\n * scope: 'appProcess',\n * include: ['src/', 'node_modules/@designable/'],\n * exclude: ['node_modules/antd']\n * })\n * ]\n * });\n * ```\n */\n\nimport type { Plugin } from 'vite';\nimport type { CssScopePluginOptions } from './types';\nimport { createPathMatcher } from './utils/path-matcher';\nimport { extractExposedPaths } from './utils/federation';\nimport { createScopePostcssPlugin } from './postcss/scope-plugin';\nimport { transformComponent } from './babel/transform';\nimport { transformHtml } from './html/transformer';\nimport { isPortalFile, transformPortal } from './babel/portal-transform';\n\n/**\n * CSS 作用域隔离插件\n * @param options - 插件配置\n * @returns Vite 插件\n */\nexport default function cssScopePlugin(options: CssScopePluginOptions): Plugin {\n const { scope, include, exclude = [] } = options;\n\n // 存储模块联邦暴露的组件路径\n let exposedComponentPaths: string[] = [];\n\n // 验证配置\n if (!scope) {\n throw new Error('[css-scope-plugin] scope 配置不能为空');\n }\n if (!include || include.length === 0) {\n throw new Error('[css-scope-plugin] include 配置不能为空');\n }\n\n // 创建路径匹配器\n const shouldTransform = createPathMatcher(include, exclude);\n\n return {\n name: 'css-scope-plugin',\n enforce: 'pre', // 在 React 插件之前执行\n\n /**\n * 配置解析完成后,提取模块联邦 exposes 路径\n */\n configResolved(resolvedConfig) {\n exposedComponentPaths = extractExposedPaths(resolvedConfig);\n },\n\n /**\n * 注入 PostCSS 插件\n */\n config() {\n return {\n css: {\n postcss: {\n plugins: [createScopePostcssPlugin(scope, shouldTransform)()]\n }\n }\n };\n },\n\n /**\n * 转换模块联邦暴露的 JSX/TSX 组件 + antd portal 容器注入\n */\n transform(code, id) {\n // 1. 处理 antd portal 容器(精确路径匹配)\n const portalMatch = isPortalFile(id);\n if (portalMatch.match && portalMatch.varName) {\n const result = transformPortal(code, id, scope, portalMatch.varName);\n if (result) {\n return { code: result, map: null };\n }\n }\n\n // 2. 处理 JSX/TSX 组件\n if (!/\\.(jsx|tsx)$/.test(id)) return null;\n\n // 检查是否是暴露的组件\n const isExposed = exposedComponentPaths.some((exposedPath) => {\n const normalizedPath = exposedPath.replace(/^\\.\\//, '');\n return id.includes(normalizedPath);\n });\n\n if (!isExposed) return null;\n\n // 转换组件\n return {\n code: transformComponent(code, id, scope),\n map: null\n };\n },\n\n /**\n * 给 index.html 的 <body> 添加作用域类名\n */\n transformIndexHtml(html) {\n return transformHtml(html, scope);\n }\n };\n}\n\n// 导出类型\nexport type { CssScopePluginOptions };\n"],"mappings":"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","names":["traverseModule","t","t","traverse","traverseModule","result","parse","traverseModule","generateModule","t","traverse","generate"]}
|