关于 fix-pseudo-modules
面向 UI5 开发者的技能,用于处理伪模块和隐式全局变量相关的检查问题。它说明如何从库导入枚举、直接导入模块,以及加载 OData 表达式扩展。
主要功能
- 01从库导入枚举和数据类型
- 02为类和控件使用直接导入
- 03为 OData 函数加载 ODataExpressionAddons
- 04涵盖 XML 视图中的 core:require
适用场景
- 01修复过时的枚举伪模块导入
- 02解决库未导出模块的问题
- 03移除隐式 OData 全局变量
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ ui5/ plugins-coding-agents --skill fix-pseudo-modules安装后在 Claude Code 中输入/fix-pseudo-modules确认已加载。
详细介绍
修复伪模块和隐式全局变量
此技能用于修复 UI5 linter 检测到、但无法自动修复的伪模块访问和隐式全局变量问题,因为这些问题需要理解正确的模块导入模式。
处理的 Linter 规则
| 规则 ID | 消息模式 | 此技能的处理方式 |
|---|---|---|
no-pseudo-modules | 已弃用的枚举伪模块“...”访问 | 通过库模块导入 |
no-pseudo-modules | 已弃用的 DataType 伪模块“...”访问 | 通过库模块导入 |
no-implicit-globals | 访问的模块“...”未由库“...”导出 | 直接导入模块 |
no-implicit-globals | 不得隐式使用 OData 内置全局符号 | 导入 ODataExpressionAddons |
何时使用
当你看到类似以下内容的 linter 输出时,应用此技能:
MyController.js:5:5 error Deprecated access of enum pseudo module 'sap/ui/core/BarColor' no-pseudo-modules
MyController.js:8:5 error Deprecated access of DataType pseudo module 'sap/ui/core/CSSSize' no-pseudo-modules
MyController.js:15:5 error Access of module 'sap/ui/unified/DateRange' not exported by library 'sap/ui/unified/library' no-implicit-globals
MyView.view.xml:20:5 error OData built-in global symbols must not be used implicitly no-implicit-globals
背景:伪模块
在 UI5 中,枚举和 DataType 过去会像模块一样访问(例如,sap/ui/core/BarColor)。这些是“伪模块”——它们不是实际存在的文件,而是在运行时通过库模块解析。在现代 UI5 中,直接导入伪模块已弃用。
修复策略
1. 枚举伪模块访问
问题:将枚举作为直接模块导入。
// Before - triggers no-pseudo-modules
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/ui/core/BarColor", // Pseudo module!
"sap/m/ListSeparators" // Pseudo module!
], function(Controller, BarColor, ListSeparators) {
"use strict";
return Controller.extend("my.app.controller.Main", {
onInit: function() {
var color = BarColor.Positive;
var separator = ListSeparators.All;
}
});
});
修复策略:从库模块导入,并将枚举作为属性访问。
// After - import from library
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/ui/core/library", // Import library
"sap/m/library" // Import library
], function(Controller, coreLibrary, mLibrary) {
"use strict";
// Extract enums from library
var BarColor = coreLibrary.BarColor;
var ListSeparators = mLibrary.ListSeparators;
return Controller.extend("my.app.controller.Main", {
onInit: function() {
var color = BarColor.Positive;
var separator = ListSeparators.All;
}
});
});
常见枚举伪模块及其所属库:
| 伪模块 | 库模块 | 枚举访问方式 |
|---|---|---|
sap/ui/core/BarColor | sap/ui/core/library | coreLibrary.BarColor |
sap/ui/core/ValueState | sap/ui/core/library | coreLibrary.ValueState |
sap/ui/core/TextDirection | sap/ui/core/library | coreLibrary.TextDirection |
sap/ui/core/TextAlign | sap/ui/core/library | coreLibrary.TextAlign |
sap/ui/core/MessageType | sap/ui/core/library | coreLibrary.MessageType |
sap/m/ListSeparators | sap/m/library | mLibrary.ListSeparators |
sap/m/ListMode | sap/m/library | mLibrary.ListMode |
sap/m/ListType | sap/m/library | mLibrary.ListType |
sap/m/ButtonType | sap/m/library | mLibrary.ButtonType |
sap/m/InputType | sap/m/library | mLibrary.InputType |
2. DataType 伪模块访问
问题:将 DataType 作为直接模块导入。
// Before - triggers no-pseudo-modules
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/ui/core/CSSSize" // DataType pseudo module!
], function(Controller, CSSSize) {
"use strict";
return Controller.extend("my.app.controller.Main", {
// Using CSSSize type
});
});
修复策略:从库模块导入。
// After - import from library
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/ui/core/library"
], function(Controller, coreLibrary) {
"use strict";
var CSSSize = coreLibrary.CSSSize;
return Controller.extend("my.app.controller.Main", {
// Using CSSSize type
});
});
常见 DataType 伪模块:
| 伪模块 | 库模块 |
|---|---|
sap/ui/core/CSSSize | sap/ui/core/library |
sap/ui/core/CSSColor | sap/ui/core/library |
sap/ui/core/URI | sap/ui/core/library |
sap/ui/core/ID | sap/ui/core/library |
sap/ui/core/Percentage | sap/ui/core/library |
3. 通过库访问隐式全局变量
问题:通过库导出访问实际上并未导出的模块。
// Before - triggers no-implicit-globals
sap.ui.define([
"sap/ui/unified/library",
"sap/ui/core/library"
], function(unifiedLibrary, coreLibrary) {
"use strict";
// These modules are NOT exported by the library!
var DateRange = unifiedLibrary.DateRange; // Error
var DOMAttribute = coreLibrary.tmpl.DOMAttribute; // Error
});
修复策略:直接导入模块。
// After - import modules directly
sap.ui.define([
"sap/ui/unified/DateRange", // Direct import
"sap/ui/core/tmpl/DOMAttribute" // Direct import
], function(DateRange, DOMAttribute) {
"use strict";
// Use directly
});
经验法则:
- 枚举和 DataType:通过库模块访问(例如,
library.EnumName) - 类/控件:直接导入(例如,
sap/ui/unified/DateRange)
4. OData 表达式附加项
问题:在表达式绑定中使用 OData 内置函数,却未导入。
// Before - triggers no-implicit-globals
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/m/Text"
], function(Controller, Text) {
"use strict";
return Controller.extend("my.app.controller.Main", {
onInit: function() {
var oText = new Text({
// Using odata.compare without import!
text: "{= odata.compare(${/value1}, ${/value2}) }"
});
}
});
});
修复策略:导入 ODataExpressionAddons 模块。
// After - import ODataExpressionAddons
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/m/Text",
"sap/ui/model/odata/ODataExpressionAddons" // Required for odata.* functions
], function(Controller, Text, ODataExpressionAddons) {
"use strict";
return Controller.extend("my.app.controller.Main", {
onInit: function() {
var oText = new Text({
// Now works - ODataExpressionAddons is imported
text: "{= odata.compare(${/value1}, ${/value2}) }"
});
}
});
});
需要导入的 OData 函数:
| OData 函数 | 可替代的直接模块 |
|---|---|
odata.compare | sap/ui/model/odata/v4/ODataUtils |
odata.fillUriTemplate | sap/ui/thirdparty/URITemplate |
odata.uriEncode | sap/ui/model/odata/ODataUtils |
注意:导入 sap/ui/model/odata/ODataExpressionAddons 是最简单的解决方案,因为它会注册所有 OData 表达式函数。
5. XML 视图中的 OData 函数
问题:在 XML 视图绑定中使用 OData 函数,却未导入。
<mvc:View
xmlns:mvc="sap.ui.core.mvc"
xmlns="sap.m">
<Text text="{= odata.compare(${/price1}, ${/price2}) }" />
</mvc:View>
修复策略:为 ODataExpressionAddons 添加 core:require。
<mvc:View
xmlns:mvc="sap.ui.core.mvc"
xmlns="sap.m"
xmlns:core="sap.ui.core"
core:require="{
ODataAddons: 'sap/ui/model/odata/ODataExpressionAddons'
}">
<Text text="{= odata.compare(${/price1}, ${/price2}) }" />
</mvc:View>
实施步骤
-
识别问题类型,查看 linter 消息:
- “enum pseudo module” → 从库中导入
- “DataType pseudo module” → 从库中导入
- “not exported by library” → 直接导入模块
- “OData built-in global” → 导入 ODataExpressionAddons
-
确定枚举/DataType 对应的库:
- 检查模块路径前缀(例如,
sap/ui/core/→sap/ui/core/library)
- 检查模块路径前缀(例如,
-
更新导入:
- 为枚举/DataType 添加库导入
- 为类添加直接模块导入
- 为 OData 函数添加 ODataExpressionAddons
-
更新代码引用:
- 从库中提取枚举/DataType:
var EnumName = library.EnumName; - 直接使用导入的模块
- 从库中提取枚举/DataType:
-
对于 XML 视图:在需要时添加
core:require
修复示例
以下面的 linter 输出为例:
MyController.js:3:5 error Deprecated access of enum pseudo module 'sap/ui/core/ValueState' no-pseudo-modules
MyController.js:4:5 error Access of module 'sap/ui/unified/DateRange' not exported by library 'sap/ui/unified/library' no-implicit-globals
MyController.js:25:5 error OData built-in global symbols must not be used implicitly no-implicit-globals
之前:
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/ui/core/ValueState",
"sap/ui/unified/library"
], function(Controller, ValueState, unifiedLibrary) {
"use strict";
var DateRange = unifiedLibrary.DateRange; // Error: not exported
return Controller.extend("my.app.controller.Main", {
onInit: function() {
var state = ValueState.Error;
var oDateRange = new DateRange({
startDate: new Date()
});
},
formatComparison: function() {
return "{= odata.compare(${/val1}, ${/val2}) }"; // Error: no import
}
});
});
之后:
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/ui/core/library", // For ValueState enum
"sap/ui/unified/DateRange", // Direct import
"sap/ui/model/odata/ODataExpressionAddons" // For odata.* functions
], function(Controller, coreLibrary, DateRange, ODataExpressionAddons) {
"use strict";
var ValueState = coreLibrary.ValueState; // Extract from library
return Controller.extend("my.app.controller.Main", {
onInit: function() {
var state = ValueState.Error;
var oDateRange = new DateRange({
startDate: new Date()
});
},
formatComparison: function() {
return "{= odata.compare(${/val1}, ${/val2}) }"; // Now works
}
});
});
备注
- 库模块只导出枚举和 DataType,不导出类/控件
- 始终通过完整模块路径直接导入控件和类
- 即使不直接使用变量,也需要导入
ODataExpressionAddons——它会在加载时注册函数 - 弃用伪模块有助于识别不恰当的依赖项,并改进加载时间优化
相关技能
- fix-js-globals:对于其他 JavaScript 全局访问模式(JS 文件上的
no-globals——例如,sap.ui.getCore()、jQuery、sap.ui.controller()),请使用 fix-js-globals - fix-control-renderer:如果渲染器代码中出现伪模块错误,并伴有渲染器特有的问题,请使用 fix-control-renderer 进行渲染器现代化处理