UI5 リンター(コード品質検査ツール)が報告した JavaScript の `no-globals` エラーを修正します。リンター自体では自動修正できないケースに対応します。 **次のような場合に使用:** - JavaScript ファイルで「Access of global variable '...' (...)」というメッセージ付きの `no-globals` ルール違反が報告される **対応できるケース(リンターは自動修正できない):** - グローバル名前空間への代入:`sap.myNamespace = {...}` - sap.ui.define 内でのグローバル名前空間の代入・読み取り - Delete 式による削除:`delete sap.something` - sap.ui.core.Core への直接アクセス(クラスとシングルトン(一つの独立した実行単位)の区別) - jQuery/$ グローバル変数:`sap/ui/thirdparty/jquery` を追加(jQuery の API 呼び出しは置き換えない) - jQuery.sap.* ユーティリティ:専用モジュールに置き換え - 条件付き・確認的なアクセス:`if (sap.ui.something)` - UI5 モジュール化されていないカスタム名前空間定義 - sap.ui.controller() ファクトリ関数:Controller.extend に変更(Fiori Elements 拡張機能は除外) - jQuery.sap.declare/require:sap.ui.define がない従来型モジュール **トリガーキーワード:** 「no-globals を修正」「グローバル変数エラー」「sap.ui.getCore」「jQuery.sap」 グローバル名前空間へのアクセスを、適切な sap.ui.define モジュールインポートに変換します。
Fix JavaScript `no-globals` errors that UI5 linter reports but cannot auto-fix. Use this skill when linter outputs: - `no-globals` rule with message "Access of global variable '...' (...)" in JS files Cases handled (linter CANNOT auto-fix): - Assignments to global namespaces: `sap.myNamespace = {...}` - Global namespace assignment/read inside sap.ui.define - Delete expressions: `delete sap.something` - sap.ui.core.Core direct access (class vs singleton) - jQuery/$ globals: add `sap/ui/thirdparty/jquery` — do NOT replace jQuery API calls - jQuery.sap.* utilities: replace with dedicated modules - Conditional/probing access: `if (sap.ui.something)` - Custom namespace definitions that aren't UI5 modules - sap.ui.controller() factory → Controller.extend (NOT Fiori Elements extensions) - jQuery.sap.declare/require: legacy modules without sap.ui.define Trigger when: "fix no-globals", "global variable error", "sap.ui.getCore", "jQuery.sap" Converts global namespace access to proper sap.ui.define module imports.
Fixes no-globals errors in JavaScript files that the UI5 linter detects but cannot auto-fix. Run npx @ui5/linter --details to get replacement suggestions and documentation links.
jQuery/$ globals — preserve jQuery API calls: When fixing jQuery/$ globals, ONLY add the sap/ui/thirdparty/jquery dependency and replace $ with jQuery. Do NOT replace standard jQuery API calls (jQuery.each, jQuery.extend, jQuery.proxy, jQuery.isEmptyObject, etc.) with native JavaScript equivalents. These are standard jQuery methods, not deprecated SAP APIs.
Case 9/10 — fix ALL globals in a single pass: When converting a file from jQuery.sap.declare/require to sap.ui.define (Case 9 or 10), you MUST also fix ALL other global-access patterns inside the file body in the same pass. There is no second pass — everything must be handled at once. Read the "Apply ALL Applicable Cases in a Single Pass" section below.
Dead code — delete, don't import: If a global assignment stores a value that is never read anywhere else in the file (e.g., this.BarColor = sap.ui.core.BarColor where this.BarColor never appears again), delete the entire statement. Do NOT add an import for it.
No intermediate forms for byId in controllers: sap.ui.getCore().byId("prefix--id") or jQuery("#prefix--id").control(0) inside a controller → this.byId("id") directly. Never leave it as Element.getElementById("prefix--id"). After replacing, remove unused Element or jQuery imports.
merge, not deepExtend: jQuery.sap.extend(true, ...) → merge() from sap/base/util/merge. The module sap/base/util/deepExtend does NOT exist.
Problem: Code creates custom namespaces on the global sap object.
// Before
sap.ui.demo = sap.ui.demo || {};
sap.ui.demo.myApp = { formatter: function() { ... } };
// After — convert to AMD module
sap.ui.define("sap/ui/demo/myApp", [], function() {
"use strict";
return { formatter: function() { ... } };
});
Problem: File is already in sap.ui.define but still assigns to a global namespace and returns the global reference (leftover from jQuery.sap.declare removal).
Not reported by linter — search manually: grep -rl "your\.project\.namespace\." webapp/ --include="*.js"
// Before
sap.ui.define([], function() {
"use strict";
com.example.app.utils.MyScripts = { runTests: function() { ... } };
return com.example.app.utils.MyScripts;
});
// After — local variable replaces global assignment
sap.ui.define([], function() {
"use strict";
var MyScripts = { runTests: function() { ... } };
return MyScripts;
});
Key rules: Extract short name from namespace end. Use var ShortName (scoping is essential). Replace all references to the full namespace within the file.
Problem: File reads from a global namespace via variable assignment instead of importing the module as a dependency.
Not reported by linter — search: grep -rn "var .* = your\.project\.namespace\." webapp/ --include="*.js"
// Before
sap.ui.define(["sap/ui/core/mvc/Controller"], function(Controller) {
var Helper = com.example.app.utils.Helper;
// ...
});
// After — add as dependency, remove local var assignment
sap.ui.define([
"com/example/app/utils/Helper",
"sap/ui/core/mvc/Controller"
], function(Helper, Controller) {
// Helper is now available via dependency parameter
});
Key rules:
com.example.app.utils.Helper → "com/example/app/utils/Helper"var X = global.namespace.X; linesap.ui.define dependency. Cycles introduced here are resolved later by fix-cyclic-depssap.ui.require callBefore replacing, read the target module's return statement:
Module's return |
How to use the dependency parameter |
|---|---|
| Returns a class | new MyClass() or MyClass.staticMethod() |
| Returns a wrapper | MyModule.getInstance() |
| Returns an instance | myInstance.method() directly |
| Returns nothing (side-effect only) | Fix the target module first — add a return |
Side-effect modules: If the target ends with }); without a return, open it, replace the global namespace assignment with a local var, and add return varName;. Then import normally in the consuming module.
Problem: sap.ui.getCore() is deprecated; its methods have moved to dedicated modules.
// Before — standalone init script (NOT a controller)
sap.ui.getCore().attachInit(function() { ... });
// After
sap.ui.define(["sap/ui/core/Core"], function(Core) {
Core.ready().then(function() { ... });
});
Note: Core.ready() is for boot-phase init scripts. Inside controllers, UI5 is already initialized — don't use it there.
Key replacements (full table in references/core-api-replacements.md):
| Deprecated | Module | Call |
|---|---|---|
sap.ui.getCore().attachInit(fn) |
sap/ui/core/Core |
Core.ready().then(fn) |
sap.ui.getCore().byId(id) |
sap/ui/core/Element |
Element.getElementById(id) — in controllers prefer this.byId() |
sap.ui.getCore().getEventBus() |
sap/ui/core/EventBus |
EventBus.getInstance() |
sap.ui.getCore().getLibraryResourceBundle(lib) |
sap/ui/core/Lib |
Lib.getResourceBundleFor(lib) |
Use the UI5 MCP Server's get_api_reference tool for additional Core method replacements.
Add sap/ui/core/Core to the dependency array and remove the global access:
// Before: var Core = sap.ui.core.Core;
// After: add "sap/ui/core/Core" to deps, use Core parameter directly
IMPORTANT: The fix is adding the import, NOT replacing jQuery API calls. jQuery.sap.* (with .sap.) = deprecated, must be replaced (Case 4b). jQuery.* (without .sap.) or jQuery(...) = standard jQuery, keep as-is.
// Before
jQuery("#el").addClass("x");
$(".container").css("display", "block");
jQuery.each(items, function(i, item) { ... });
// After — add dependency, rename $ to jQuery, keep all API calls unchanged
sap.ui.define([..., "sap/ui/thirdparty/jquery"], function(..., jQuery) {
jQuery("#el").addClass("x");
jQuery(".container").css("display", "block");
jQuery.each(items, function(i, item) { ... });
});
NEVER replace these standard jQuery methods — they are not deprecated in UI5: jQuery.each, jQuery.extend, jQuery.proxy, jQuery.isEmptyObject, jQuery.isArray, jQuery.inArray, jQuery.grep, jQuery.map, jQuery.type, jQuery.trim.
Problem: jQuery("#prefix--id").control(0) or Element.closestTo() to get a UI5 control inside a controller.
Detection patterns — all collapse to this.byId("<local-id>"):
jQuery("#<anything>--<id>").control(0)Element.closestTo(jQuery("#<anything>--<id>")[0])sap.ui.getCore().byId("<full-id>") where ID contains view prefixElement.getElementById("<full-id>") where ID contains --The local ID is the part after the last --. After replacing, remove unused jQuery/Element imports.
Problem: jQuery.sap.* calls are deprecated UI5 utilities with dedicated replacement modules.
// Before
jQuery.sap.log.info("msg");
var sId = jQuery.sap.uid();
// After
sap.ui.define([..., "sap/base/Log", "sap/base/util/uid"], function(..., Log, uid) {
Log.info("msg");
var sId = uid();
});
Run npx @ui5/linter --details for suggested replacements. Full table in references/core-api-replacements.md.
jQuery.sap.extend decision:
true as first arg) → sap/base/util/merge → merge({}, obj1, obj2)Object.assign({}, obj1, obj2) (no import needed)jQuery.extend(...) (introduces unnecessary dependency)sap/base/util/deepExtend (does NOT exist)Problem: Code checks if a global exists: if (sap.ui.fl && sap.ui.fl.Utils) { ... }
Fix: For always-available modules, add as sap.ui.define dependency. For truly optional modules, use synchronous sap.ui.require:
var FlUtils = sap.ui.require("sap/ui/fl/Utils");
if (FlUtils) { FlUtils.getComponentClassName(this); }
For lazy loading, use async: sap.ui.require(["module/path"], function(Mod) { ... }).
Same pattern as Case 1 but for non-SAP namespaces (window.mycompany.myapp = {...}). Convert to sap.ui.define module returning the object. Consumers import via dependency.
// Before — global reference as string
value: { path: "/amount", type: "sap.ui.model.type.Float" }
// After — import type module, use class reference
value: { path: "/amount", type: new FloatType() } // FloatType from "sap/ui/model/type/Float"
delete sap.ui.core.someTempProperty — usually a code smell. Remove entirely or use a local object.
Scope: Plain controller definitions. NOT Fiori Elements V2 extensions (use fix-fiori-elements-extensions for those).
Detection: grep -rn 'sap\.ui\.controller(' webapp/ --include="*.js"
sap.ui.controller("name", {...}) = definition → fix heresap.ui.controller("name") = instance lookup → document in MODERNIZATION-ISSUES.md// Before
sap.ui.define(["sap/m/MessageBox"], function(MessageBox) {
return sap.ui.controller("my.app.controller.Main", { ... });
});
// After — add Controller dep, replace factory with extend
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/m/MessageBox"
], function(Controller, MessageBox) {
return Controller.extend("my.app.controller.Main", { ... });
});
// Before
jQuery.sap.declare("my.app.controller.Detail");
jQuery.sap.require("sap.ui.core.mvc.Controller");
sap.ui.controller("my.app.controller.Detail", { onInit: function() { ... } });
// After
sap.ui.define(["sap/ui/core/mvc/Controller"], function(Controller) {
"use strict";
return Controller.extend("my.app.controller.Detail", { onInit: function() { ... } });
});
Steps: Remove jQuery.sap.declare/require. Wrap in sap.ui.define. Convert dot-notation deps to slash-notation. Replace sap.ui.controller with Controller.extend. Add return. Add "use strict". Apply all inline fixes to file body (see "Apply ALL" section).
return: Controller.extend() only returns the class — always add return before itreturnMODERNIZATION-ISSUES.mdSame structural conversion as Case 9 Pattern B but for non-controller modules:
// Before
jQuery.sap.declare("my.app.util.Formatter");
jQuery.sap.require("sap.ui.core.format.DateFormat");
my.app.util.Formatter = { formatDate: function(oDate) { ... } };
// After
sap.ui.define(["sap/ui/core/format/DateFormat"], function(DateFormat) {
"use strict";
return { formatDate: function(oDate) { ... } };
});
Key rules: Remove jQuery.sap.declare. Convert jQuery.sap.require to deps. Remove global assignment, return the object. If already has sap.ui.define, merge remaining requires into existing dep array. Dynamic/conditional requires → sap.ui.require(["..."], callback). Multiple declares or unclear exports → flag for manual review. Apply all inline fixes (see "Apply ALL" section).
Problem: Runtime modules like sap.ushell.Container accessed via global namespace chains.
// Before
if (sap.ushell && sap.ushell.Container) {
sap.ushell.Container.getService("CrossApplicationNavigation");
}
// After — add as dependency
sap.ui.define(["sap/ushell/Container", ...], function(Container, ...) {
if (Container && Container.getService) {
Container.getService("CrossApplicationNavigation");
}
});
Test-side: Stub the imported module directly with sinon. Do NOT set up global namespace chains (window.sap.ushell = {...}). sinon and QUnit are Test Starter globals — no import needed.
sap.ui.define(["sap/ushell/Container"], function(Container) {
var oSandbox = sinon.createSandbox();
QUnit.test("...", function(assert) {
oSandbox.stub(Container, "setDirtyFlag");
// ...
});
});
After modernizing jQuery.sap.sjax to native XMLHttpRequest, always guard xhr.responseText with a status check:
var xhr = new XMLHttpRequest();
xhr.open("GET", sUrl, false);
xhr.send();
if (xhr.readyState === 4 && xhr.status === 200) {
var oData = JSON.parse(xhr.responseText);
} else {
Log.error("Failed to load: " + sUrl);
}
| Context | Fallback on failure |
|---|---|
| Mock server response handler | oXhr.respondJSON(200, {}, JSON.stringify({"d": {"results": []}})) |
| JSON.parse of response | Return {} (lets existing if (oResponse.data) guards work) |
| Init-time config loading | Early return with Log.error(...) |
When a file triggers Case 9 or 10, fix ALL global-access patterns in the same pass:
jQuery("#...") or jQuery(...) calls? → Case 4a or 4sap.ui.getCore().byId(...) calls? → Case 2, then Case 4a if in controllerjQuery.sap.* calls? → Case 4bsap.ui.model.*, sap.m.*, sap.ui.core.* inline class references? → dependency importsthis.X = importedModule.X where this.X is never read elsewhere? → DELETE (dead code)npx @ui5/linter --details to get replacement suggestionsthis.byId(), remove unused importsDependency insertion position — critical: Always add new dependencies at the beginning of the array (and corresponding parameters at the beginning of the function). Many legacy files have dep/param count mismatches (trailing side-effect imports without parameters). Inserting at the end shifts existing mappings; inserting at the beginning preserves them.
// Before (3 deps, 2 params — mismatch is common in legacy code)
sap.ui.define(["sap/ui/core/mvc/Controller", "sap/m/MessageToast", "some/sideEffect/Module"
], function(Controller, MessageToast) { ... });
// After — new dep added at BEGINNING
sap.ui.define(["sap/ui/core/Element", "sap/ui/core/mvc/Controller", "sap/m/MessageToast", "some/sideEffect/Module"
], function(Element, Controller, MessageToast) { ... });
Parameter names should match the module's default export name (e.g., Log for sap/base/Log)
QUnit, sinon are intentionally allowed globals in test files
sap.ui.define, sap.ui.require, sap.ui.loader.config are allowed globals
Use sap.ui.require("module/path") (sync, returns undefined if not loaded) for optional deps
Use sap.ui.require(["module/path"], callback) (async) for lazy loading
For a comprehensive before/after example combining multiple case types, read references/example-fix-session.md.
sap.ui.controller() in Fiori Elements V2 apps with registerControllerExtensions or manifest sap.ui.controllerExtensionsno-pseudo-modules and no-implicit-globals errors (enum imports, DataType imports, OData expression functions)no-deprecated-control-renderer-declaration, apiVersion, IconPool, rerender)no-globals in XML views/fragments (formatters, event handlers via core:require)sap.*). Cases 1b and 1c overlap with patterns 1-4 in that skill.sap.ui.require instead of normal sap.ui.define deps原文・著作権は Anthropic および各プラグイン作者に帰属します。日本語訳は Claude API による自動翻訳です。