Fix Control Renderer

作者 UI52b8c4a944e39無授權條款收錄於 2026年10月8日更新於 2026年10月8日

Fix Control renderer issues that UI5 linter reports but cannot auto-fix. Use this skill when linter outputs these rules: - `no-deprecated-control-renderer-declaration` - For missing renderer declaration, string-based renderer declaration, implicit renderer auto-discovery (removed in modern UI5) - `no-deprecated-api` - For missing apiVersion:2 in renderer objects, missing IconPool import when using oRm.icon(), deprecated rerender() override. NOTE: For Library.init() apiVersion errors, use fix-library-init instead. - `ui5-class-declaration` - For non-static renderer property in ES6 classes Trigger on: "missing a renderer declaration", "Deprecated declaration of renderer", "deprecated renderer", "apiVersion" (in renderer context), "IconPool", "rerender", "renderer must be a static property" Converts legacy renderer patterns to modern apiVersion: 2 format with proper module imports.

AI 產生的概覽

修復 UI5 linter 回報的控件渲染器問題,將舊式渲染器轉換為 apiVersion 2。

功能
此技能引導代理修復 UI5 linter 回報但無法自動修復的 UI5 控件渲染器問題。它將特定的 linter 規則與訊息對應到程式碼修改,例如新增渲染器宣告、把字串形式的渲染器參照改為模組匯入、加入 apiVersion: 2、為 oRm.icon() 匯入 IconPool、以生命週期鉤子取代 rerender() 覆寫,以及將渲染器屬性設為靜態。它另外附有一份參考檔案,內含完整的 apiVersion 1 到 apiVersion 2 方法轉換表。
適用情境
當 UI5 linter 輸出包含與渲染器相關的發現時使用,例如 no-deprecated-control-renderer-declaration、渲染器情境中的 no-deprecated-api,或關於非靜態渲染器的 ui5-class-declaration。它用於將舊式 UI5 控件渲染器現代化為語意渲染 API。
執行需求
不隨附指令碼,僅為指示性內容。它假定可使用 UI5 linter(例如透過 npx @ui5/linter),並能存取專案的 UI5 控件與渲染器原始檔。

Fix Control Renderer Issues

This skill fixes Control renderer issues that the UI5 linter detects but cannot auto-fix because they require understanding of the control's rendering behavior and module dependencies.

Linter Rules Handled

Rule IDMessage PatternThis Skill's Action
no-deprecated-control-renderer-declarationControl '...' is missing a renderer declarationAdd renderer: null or import renderer
no-deprecated-control-renderer-declarationDeprecated declaration of renderer '...' for control '...'Import renderer module and assign directly
no-deprecated-apiUse of deprecated renderer detected. Define explicitly the {apiVersion: 2}Add apiVersion: 2 to renderer object
no-deprecated-api"sap/ui/core/IconPool" module must be imported when using RenderManager's icon() methodAdd IconPool import
no-deprecated-apiOverride of deprecated method 'rerender' in control '...'Remove override, move code to lifecycle hooks
ui5-class-declarationThe control renderer must be a static propertyMake renderer property static

When to Use

Apply this skill when you see linter output like:

MyControl.js:5:1 error Control 'my.app.control.MyControl' is missing a renderer declaration  no-deprecated-control-renderer-declarationMyControl.js:10:5 error Deprecated declaration of renderer 'my.app.control.MyControlRenderer' for control 'my.app.control.MyControl'  no-deprecated-control-renderer-declarationMyControl.js:15:5 error Use of deprecated renderer detected. Define explicitly the {apiVersion: 2} parameter  no-deprecated-apiMyControl.js:20:5 error "sap/ui/core/IconPool" module must be imported when using RenderManager's icon() method  no-deprecated-apiMyControl.js:25:5 warning The control renderer of 'MyControl' must be a static property  ui5-class-declaration

Background: Why apiVersion: 2?

UI5's rendering framework evolved from an immediate DOM manipulation model (apiVersion 1) to a semantic rendering model (apiVersion 2 and 4). The key differences:

  • apiVersion 1 (deprecated): Direct DOM manipulation via oRm.write(), oRm.writeAttribute(), etc.
  • apiVersion 2: Semantic methods like oRm.openStart(), oRm.openEnd(), oRm.text(), oRm.close()
  • apiVersion 4: Same as 2, with additional performance optimizations (for modern UI5)

Without explicit apiVersion, UI5 assumes legacy rendering which causes synchronous loading and performance issues.

Implicit Renderer Auto-Discovery (Removed in modern UI5)

In UI5 1.x, if a control doesn't declare a renderer property, the framework automatically tries to load a renderer module by appending Renderer to the control's module path. For example, for sap/m/Button, it checks whether sap/m/ButtonRenderer exists — if so, that module is loaded and used as the renderer.

This implicit auto-discovery is removed in modern UI5. Every control must explicitly declare its renderer. If a control relied on auto-discovery and has no renderer property, it will break at runtime. The linter flags this as no-deprecated-control-renderer-declaration with the message "Control '...' is missing a renderer declaration".

The modernization workflow is: check whether a <ControlName>Renderer module exists at the default path → if yes, import it via sap.ui.define → assign it to the renderer property.

Fix Strategy

1. Missing Renderer Declaration

Problem: Control class doesn't declare a renderer at all.

javascript
// Before - triggers no-deprecated-control-renderer-declarationsap.ui.define([    "sap/ui/core/Control"], function(Control) {    "use strict";
    return Control.extend("my.app.control.MyControl", {        metadata: {            properties: { ... }        }        // No renderer declaration!    });});

Fix Strategy A - No rendering needed (control is abstract or uses child controls):

javascript
// After - explicitly declare no renderersap.ui.define([    "sap/ui/core/Control"], function(Control) {    "use strict";
    return Control.extend("my.app.control.MyControl", {        metadata: {            properties: { ... }        },
        renderer: null    });});

Fix Strategy B - Renderer exists in separate file (including implicit auto-discovery):

In UI5 1.x, many controls rely on the framework's implicit auto-discovery — they have no renderer property, but a <ControlName>Renderer.js file exists at the default path and gets loaded automatically. Since this auto-discovery is removed in modern UI5, you need to make the import explicit.

How to find the renderer:

  1. Derive the expected renderer path: take the control's module path and append Renderer. For my/app/control/MyControl, check for my/app/control/MyControlRenderer.
  2. Look for the file in the project (e.g., MyControlRenderer.js in the same directory as the control).
  3. If the renderer file exists, import it and assign it. If it doesn't exist, use Fix Strategy A (renderer: null) or Fix Strategy C (inline renderer).
javascript
// After - import and assign the renderer modulesap.ui.define([    "sap/ui/core/Control",    "./MyControlRenderer"], function(Control, MyControlRenderer) {    "use strict";
    return Control.extend("my.app.control.MyControl", {        metadata: {            properties: { ... }        },
        renderer: MyControlRenderer    });});

Important: After importing the renderer, also check whether the renderer module itself has apiVersion: 2. If not, that's a separate linter finding — see section 3 "Missing apiVersion in Renderer" below.

Fix Strategy C - Add inline renderer:

javascript
// After - define renderer inline with apiVersion: 2sap.ui.define([    "sap/ui/core/Control"], function(Control) {    "use strict";
    return Control.extend("my.app.control.MyControl", {        metadata: {            properties: { ... }        },
        renderer: {            apiVersion: 2,            render: function(oRm, oControl) {                oRm.openStart("div", oControl);                oRm.class("myControl");                oRm.openEnd();                // Render content here                oRm.close("div");            }        }    });});

2. String-Based Renderer Declaration

Problem: Renderer declared as string causes synchronous loading.

javascript
// Before - triggers no-deprecated-control-renderer-declarationsap.ui.define([    "sap/ui/core/Control"], function(Control) {    "use strict";
    return Control.extend("my.app.control.MyControl", {        metadata: { ... },
        renderer: "my.app.control.MyControlRenderer"  // String = sync loading!    });});

Fix Strategy: Import the renderer module and assign directly.

javascript
// After - import renderer modulesap.ui.define([    "sap/ui/core/Control",    "my/app/control/MyControlRenderer"], function(Control, MyControlRenderer) {    "use strict";
    return Control.extend("my.app.control.MyControl", {        metadata: { ... },
        renderer: MyControlRenderer    });});

3. Missing apiVersion in Renderer

Problem: Renderer object or function without apiVersion declaration.

javascript
// Before - triggers no-deprecated-apirenderer: {    render: function(oRm, oControl) {        oRm.write("<div");        oRm.writeControlData(oControl);        oRm.write(">");        oRm.write("</div>");    }}
// OR - function without apiVersionrenderer: function(oRm, oControl) {    oRm.write("<div>");    oRm.write("</div>");}

Fix Strategy: Add apiVersion: 2 and convert to semantic rendering API.

javascript
// After - with apiVersion: 2 and semantic methodsrenderer: {    apiVersion: 2,    render: function(oRm, oControl) {        oRm.openStart("div", oControl);        oRm.openEnd();        oRm.close("div");    }}

apiVersion 1 to apiVersion 2 Method Conversions:

Old Method (apiVersion 1)New Method (apiVersion 2)
oRm.write("<tag")oRm.openStart("tag") or oRm.voidStart("tag")
oRm.write(">")oRm.openEnd() or oRm.voidEnd()
oRm.write("</tag>")oRm.close("tag")
oRm.write(text)oRm.text(text)
oRm.writeControlData(oCtrl)Pass control as 2nd arg: oRm.openStart("div", oControl)
oRm.addClass("cls")oRm.class("cls")
oRm.writeAttribute("name", val)oRm.attr("name", val)

For the complete conversion table with examples, read references/renderer-api-mapping.md.

4. Missing IconPool Import

Problem: Using oRm.icon() without importing IconPool.

javascript
// Before - triggers no-deprecated-apisap.ui.define([    "sap/ui/core/Control"], function(Control) {    "use strict";
    return Control.extend("my.app.control.MyControl", {        renderer: {            apiVersion: 2,            render: function(oRm, oControl) {                oRm.openStart("div", oControl);                oRm.openEnd();                oRm.icon("sap-icon://accept");  // IconPool not imported!                oRm.close("div");            }        }    });});

Fix Strategy: Add IconPool to the imports. The import is required even though it's not directly referenced in code.

javascript
// After - IconPool importedsap.ui.define([    "sap/ui/core/Control",    "sap/ui/core/IconPool"  // Required for oRm.icon()], function(Control, IconPool) {    "use strict";
    return Control.extend("my.app.control.MyControl", {        renderer: {            apiVersion: 2,            render: function(oRm, oControl) {                oRm.openStart("div", oControl);                oRm.openEnd();                oRm.icon("sap-icon://accept");                oRm.close("div");            }        }    });});

5. Deprecated rerender() Override

Problem: Overriding rerender() method no longer works in UI5 1.121+.

javascript
// Before - triggers no-deprecated-apisap.ui.define([    "sap/ui/core/Control"], function(Control) {    "use strict";
    return Control.extend("my.app.control.MyControl", {        renderer: { ... },
        rerender: function() {            // Custom logic before rerendering            this._prepareForRender();            Control.prototype.rerender.apply(this, arguments);            // Custom logic after rerendering            this._finishRender();        }    });});

Fix Strategy: Move pre-render logic to onBeforeRendering() and post-render logic to onAfterRendering().

javascript
// After - use lifecycle hooks insteadsap.ui.define([    "sap/ui/core/Control"], function(Control) {    "use strict";
    return Control.extend("my.app.control.MyControl", {        renderer: { ... },
        onBeforeRendering: function() {            // Called before each render (initial + re-renders)            this._prepareForRender();        },
        onAfterRendering: function() {            // Called after each render (initial + re-renders)            this._finishRender();        }    });});

Implementation Steps

  1. Run linter with --details to get additional context:

    bash
    npx @ui5/linter --details
  2. Identify the error pattern from linter output (rule ID + message)

  3. Determine the control's rendering needs:

    • Does the control need custom rendering?
    • Is there an existing separate renderer file? Check the default path: <ControlName>Renderer.js in the same directory (UI5 1.x auto-discovery path)
    • Does the renderer use oRm.icon()?
  4. Apply the appropriate transformation:

    • For missing declaration: Check if <ControlName>Renderer.js exists at the default path (auto-discovery). If yes, import and assign it. If no, add renderer: null or create an inline renderer
    • For string declaration: Convert to module import
    • For missing apiVersion: Add apiVersion: 2 and convert render methods
    • For IconPool: Add the import to sap.ui.define dependencies
    • For rerender override: Move logic to lifecycle hooks
    • For non-static: Add static keyword (ES6 classes)
  5. Verify the fix by re-running the linter

Example Fix Session

Given linter output:

npx @ui5/linter --details
MyControl.js:5:1 error Deprecated declaration of renderer 'my.app.control.MyControlRenderer' for control 'my.app.control.MyControl'  no-deprecated-control-renderer-declaration  Details: Defining the control renderer by its name may lead to synchronous loading of the control renderer module.MyControl.js:20:5 error Use of deprecated renderer detected. Define explicitly the {apiVersion: 2} parameter in the renderer object  no-deprecated-api  Details: See: https://ui5.sap.com/#/topic/c9ab34570cc14ea5ab72a6d1a4a03e3f

Before:

javascript
sap.ui.define([    "sap/ui/core/Control"], function(Control) {    "use strict";
    return Control.extend("my.app.control.MyControl", {        metadata: {            properties: {                text: { type: "string", defaultValue: "" }            }        },
        renderer: "my.app.control.MyControlRenderer"    });});
// MyControlRenderer.js (separate file)sap.ui.define([], function() {    "use strict";
    var MyControlRenderer = {};
    MyControlRenderer.render = function(oRm, oControl) {        oRm.write("<div");        oRm.writeControlData(oControl);        oRm.addClass("myControl");        oRm.writeClasses();        oRm.write(">");        oRm.writeEscaped(oControl.getText());        oRm.write("</div>");    };
    return MyControlRenderer;});

After:

javascript
sap.ui.define([    "sap/ui/core/Control",    "./MyControlRenderer"], function(Control, MyControlRenderer) {    "use strict";
    return Control.extend("my.app.control.MyControl", {        metadata: {            properties: {                text: { type: "string", defaultValue: "" }            }        },
        renderer: MyControlRenderer    });});
// MyControlRenderer.js (separate file) - updatedsap.ui.define([], function() {    "use strict";
    var MyControlRenderer = {        apiVersion: 2    };
    MyControlRenderer.render = function(oRm, oControl) {        oRm.openStart("div", oControl);        oRm.class("myControl");        oRm.openEnd();        oRm.text(oControl.getText());        oRm.close("div");    };
    return MyControlRenderer;});

Notes

  • Controls that extend these base classes do NOT need a renderer declaration:

    • sap/ui/core/mvc/View
    • sap/ui/core/XMLComposite
    • sap/ui/core/webc/WebComponent
    • sap/uxap/BlockBase
  • apiVersion: 4 is also valid and provides additional optimizations for modern UI5

  • When converting from apiVersion 1 to 2, ensure all write() calls are properly converted to semantic methods

  • The IconPool import is needed at module load time for icon font registration, even if IconPool variable is not used in code

Related Skills

  • fix-js-globals: For no-globals errors in non-renderer JavaScript files (e.g., controllers, utilities), use fix-js-globals — it handles sap.ui.define dependency additions and global access replacement
  • fix-pseudo-modules: If renderer code also has enum or DataType pseudo module imports, use fix-pseudo-modules for those specific issues
  • fix-library-init: For Library.init() / Lib.init() apiVersion errors ("Deprecated call to ... Use the {apiVersion: 2} parameter"), use fix-library-init — it handles library initialization, not renderer objects

來源與署名

來源:UI5/plugins-coding-agents位於plugins/ui5-modernization/skills/fix-control-renderer提交2b8c4a9

授權條款: 無授權條款

內容歸原作者所有。SourceWeft 從公開儲存庫中收錄這些內容。

檢舉或申請下架