fix(XSender): 用 @layer 隔离 x-sender CSS,修复污染 ant-design-vue 样式问题 (#458)#463
fix(XSender): 用 @layer 隔离 x-sender CSS,修复污染 ant-design-vue 样式问题 (#458)#463SmartBigFeng wants to merge 1 commit intoelement-plus-x:mainfrom
Conversation
📝 WalkthroughWalkthroughAdded a new Vite plugin that wraps CSS files containing Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~8 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/core/.build/plugins/xSenderCssLayer.ts`:
- Around line 11-13: The transform hook in xSenderCssLayer.ts currently checks
id.includes('x-sender') and id.endsWith('.css'), which misses Vite query
suffixes and overmatches; update the matcher in transform to first strip the
query string (e.g., const clean = id.split('?')[0]) and then perform a precise
path/name check on that cleaned id (for example using endsWith('XSender.css') or
a path-aware test rather than includes) so CSS module requests like
XSender.css?used or ?inline are matched and unrelated paths are not.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 8cd5059b-90d1-4664-8c1a-88bc3402c11d
📒 Files selected for processing (2)
packages/core/.build/plugins/index.tspackages/core/.build/plugins/xSenderCssLayer.ts
| transform(code, id) { | ||
| if (id.includes('x-sender') && id.endsWith('.css')) { | ||
| return { |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In Vite plugin transform(code, id), can CSS module idvalues include query suffixes (for example?used, ?inline, or other query parameters)? What is the recommended pattern for reliably matching .css files from a specific package?
💡 Result:
Web search failed: Server error: no LLM provider could handle the message
🏁 Script executed:
# First, let's examine the actual plugin file
find . -name "xSenderCssLayer.ts" -o -name "*xSender*" | head -20Repository: element-plus-x/Element-Plus-X
Length of output: 1909
🏁 Script executed:
# Look at the plugin file content
cat packages/core/.build/plugins/xSenderCssLayer.ts 2>/dev/null || find . -path "*/.build/plugins/*" -name "*.ts" | head -5Repository: element-plus-x/Element-Plus-X
Length of output: 1909
🏁 Script executed:
# Search for other Vite plugin transform patterns in the codebase
rg "transform\s*\(\s*code\s*,\s*id" --type ts -A 3 | head -50Repository: element-plus-x/Element-Plus-X
Length of output: 1909
🏁 Script executed:
# Check if there are any tests or usage examples for this plugin
fd "xSender" -e test.ts -e spec.ts -e test.js -e vite.config.tsRepository: element-plus-x/Element-Plus-X
Length of output: 1909
🌐 Web query:
Vite plugin transform hook CSS module id query parameters ?used ?inline
💡 Result:
In Vite's CSS plugin, the module ID for CSS files (including CSS modules) can include specific query parameters during the transform hook: - ?used: Internal query parameter automatically appended by Vite's import analysis plugin to CSS imports that use the default export. It signals that the CSS string content should be exported (e.g., export default "css content"), enabling tree-shaking of unused CSS strings by esbuild/Rollup. Without ?used, the module may export an empty string or nothing to avoid unnecessary CSS inclusion. This is used in scenarios like import.meta.glob for CSS or default imports needing the content. Note: Vite 5+ removed default CSS exports, making ?inline required for string access. - ?inline: User-specified query to return processed CSS as a string default export instead of injecting via <style> tag (disables automatic injection). Commonly used for manual CSS handling, e.g., import css from './styles.module.css?inline'. Works with CSS modules but returns the CSS string (losing class exports unless combined with plugins). These appear in the id string in the transform hook filter/handler: transform: [{ filter: /?.(used|inline)/ }, handler(src, id) { / id includes ?used or ?inline */ } ]. They help plugins detect/respond to CSS handling modes, e.g., custom inlining or optimization. ?used is internal (not for direct user use; auto-managed), while ?inline is public. For CSS modules with both needs (classes + inline CSS), use plugins like vite-plugin-css-injected-by-js or vite-css-modules.
Citations:
- 1: fix(glob): css imports injecting a ?used query to export the css string vitejs/vite#6949
- 2: fix(build-import-analysis): should not append ?used when css request has ?url or ?raw vitejs/vite#11910
- 3: https://github.com/vitejs/vite/blob/main/packages/vite/src/node/plugins/css.ts
- 4: https://vite.dev/guide/features
- 5: Inline styles from css-modules in bundle vitejs/vite#18780
🌐 Web query:
Vite plugin reliable pattern match CSS files id endsWith
💡 Result:
In Vite plugins, the reliable pattern to match CSS files by their module ID (where the ID ends with '.css') uses the transform hook's filter option with a RegExp. Use this structure: export default function myPlugin { return { name: 'my-css-plugin', transform(code, id) { if (id.endsWith('.css')) { // Your transform logic for CSS files return { code: transformedCode, map: null // or source map } } } } } For newer Vite versions (5+), use the structured transform filter: import { regexFilter } from '@rolldown/pluginutils' // or similar utility export default function myPlugin { return { name: 'my-css-plugin', transform: { filter: regexFilter(/.css$/), handler(code, id) { // Transform logic return { code: transformedCode, map: null } } } } } This matches any module ID ending with '.css'. The id is the full resolved module path/identifier, so endsWith('.css') reliably identifies CSS files. id.endsWith('.css') is safe as id is always a string in Vite plugin hooks.
Citations:
🌐 Web query:
best practice Vite plugin id.split('?') CSS matching third party packages
💡 Result:
In Vite plugins, particularly for handling CSS processing or CSS modules in third-party packages from node_modules, a common best practice is to use conditional filtering in plugin options like include or exclude functions. These functions receive the module id (full path) and parse it using id.split('?') to get the base filename without Vite's internal query parameters (like ?direct or ?html-proxy-cache), then check properties like id.includes('node_modules') to selectively apply transformations. Example from vite-plugin-for-load-css-module for third-party SCSS modules (source 1): include: (id) => (id.endsWith('less') && !id.includes('node_modules')) || (id.endsWith('scss') && id.includes('node_modules')) This pattern ensures: - App CSS (non-node_modules) gets standard processing. - Third-party CSS (node_modules) gets special handling only when needed, avoiding conflicts with relative paths or PostCSS. Vite's CSS pipeline adds query params during processing (sources 14, 19, 22), so splitting isolates the source path for reliable matching. Use enforce: 'pre' for custom CSS plugins to run before Vite's vite:css (source 18). For CSS modules specifically, plugins like vite-css-modules (sources 2,4,27) integrate better with Vite's module graph. Official Vite docs recommend css.modules.include/exclude for scoped processing (vitejs.dev/config/#css-modules-include). Custom plugins follow Rollup/Vite plugin conventions: parse id cleanly before path checks.
Citations:
- 1: How should third-party dependent css be handled vitejs/vite#8284
- 2: URL Query Parameter with .scss causes vite to fail vitejs/vite#6894
- 3: Add a moduleid query prefix for custom loader / transformer (and a query tag convention to switch on/off transformations) vitejs/vite#8523
- 4: fix: handle css transform split '?' vitejs/vite#6912
- 5: fix(css): remove
?directin id for postcss process vitejs/vite#10514 - 6: https://www.npmjs.com/package/vite-css-modules/v/1.1.0
Handle Vite CSS query suffixes in the matcher.
On line 12, id.endsWith('.css') will miss CSS module IDs with query parameters (e.g., ...XSender.css?used, ...XSender.css?inline), preventing the layer wrapper from applying and reintroducing style pollution. Also, includes('x-sender') is overly broad and can match unrelated paths.
Split the ID on the query string separator first, then apply precise path matching:
🔧 Proposed fix
transform(code, id) {
- if (id.includes('x-sender') && id.endsWith('.css')) {
+ const [path] = id.split('?', 1);
+ if (/(^|[\\/])x-sender([\\/]|$)/.test(path) && path.endsWith('.css')) {
return {
code: `@layer element-plus-x-third-party {
${code}
}`,
map: null
};
}
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| transform(code, id) { | |
| if (id.includes('x-sender') && id.endsWith('.css')) { | |
| return { | |
| transform(code, id) { | |
| const [path] = id.split('?', 1); | |
| if (/(^|[\\/])x-sender([\\/]|$)/.test(path) && path.endsWith('.css')) { | |
| return { | |
| code: `@layer element-plus-x-third-party { | |
| ${code} | |
| }`, | |
| map: null | |
| }; | |
| } | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/core/.build/plugins/xSenderCssLayer.ts` around lines 11 - 13, The
transform hook in xSenderCssLayer.ts currently checks id.includes('x-sender')
and id.endsWith('.css'), which misses Vite query suffixes and overmatches;
update the matcher in transform to first strip the query string (e.g., const
clean = id.split('?')[0]) and then perform a precise path/name check on that
cleaned id (for example using endsWith('XSender.css') or a path-aware test
rather than includes) so CSS module requests like XSender.css?used or ?inline
are matched and unrelated paths are not.
XSender组件引入的第三方库x-sender样式文件内部包含ant-spin等css样式,会污染ant-design-vue的原生样式
使用@layer隔离样式,后续想修改XSender组件的ant等样式可使用样式穿透
效果如下

Summary by CodeRabbit