mcpField
F
fix-control-renderer

fix-control-renderer

github.com/ui5開発44144 回インストール1 週間前に更新
リポジトリ

fix-control-renderer について

fix-control-rendererは、UI5のリンターが報告するコントロールのレンダラー問題に対応する開発スキルです。レンダリング動作の理解が必要な、宣言やAPIバージョン、インポート、ライフサイクルフック、静的プロパティの変更を案内します。

主な機能

  1. 01レンダラー宣言の不足を修正
  2. 02文字列による宣言をインポートに変更
  3. 03レンダラーをapiVersion 2に更新
  4. 04必要なIconPoolインポートを追加
  5. 05rerender処理をライフサイクルフックへ移動
  6. 06レンダラープロパティを静的に設定

活用シーン

  1. 01UI5リンターのレンダラー指摘に対応
  2. 02自動検出に依存するコントロールを更新
  3. 03リンター再実行でレンダリング変更を検証

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/ui5/plugins-coding-agents --skill fix-control-renderer

インストール後、Claude Code で/fix-control-rendererを入力して読み込まれたか確認します。

同梱ファイルreferences/renderer-api-mapping.md

詳細

Control レンダラーの問題を修正する

このスキルは、UI5 リンターが検出するものの、コントロールのレンダリング動作やモジュール依存関係の理解が必要なため自動修正できない、Control レンダラーの問題を修正します。

対応するリンタールール

ルール IDメッセージパターンこのスキルによる対応
no-deprecated-control-renderer-declarationControl '...' is missing a renderer declarationrenderer: null を追加するか、レンダラーをインポートします
no-deprecated-control-renderer-declarationDeprecated declaration of renderer '...' for control '...'レンダラーモジュールをインポートし、直接割り当てます
no-deprecated-apiUse of deprecated renderer detected. Define explicitly the {apiVersion: 2}レンダラーオブジェクトに apiVersion: 2 を追加します
no-deprecated-api"sap/ui/core/IconPool" module must be imported when using RenderManager's icon() methodIconPool のインポートを追加します
no-deprecated-apiOverride of deprecated method 'rerender' in control '...'オーバーライドを削除し、コードをライフサイクルフックに移動します
ui5-class-declarationThe control renderer must be a static propertyrenderer プロパティを static にします

使用する場面

次のようなリンター出力が表示された場合に、このスキルを適用してください。

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

背景:なぜ apiVersion: 2 なのか?

UI5 のレンダリングフレームワークは、即時 DOM 操作モデル(apiVersion 1)からセマンティックレンダリングモデル(apiVersion 2 および 4)へと進化しました。主な違いは次のとおりです。

  • apiVersion 1(非推奨):oRm.write() や oRm.writeAttribute() などによる直接的な DOM 操作
  • apiVersion 2:oRm.openStart()、oRm.openEnd()、oRm.text()、oRm.close() などのセマンティックなメソッド
  • apiVersion 4:2 と同じですが、(最新の UI5 向けの)パフォーマンス最適化が追加されています

apiVersion を明示しない場合、UI5 はレガシーなレンダリングを想定するため、同期読み込みやパフォーマンスの問題が発生します。

暗黙的なレンダラーの自動検出(最新の UI5 では削除)

UI5 1.x では、コントロールに renderer プロパティが宣言されていない場合、フレームワークはコントロールのモジュールパスに Renderer を追加して、レンダラーモジュールを自動的に読み込もうとします。たとえば sap/m/Button の場合、sap/m/ButtonRenderer が存在するかを確認し、存在すれば、そのモジュールを読み込んでレンダラーとして使用します。

この暗黙的な自動検出は最新の UI5 では削除されています。すべてのコントロールでレンダラーを明示的に宣言する必要があります。自動検出に依存していて renderer プロパティがないコントロールは、実行時に動作しなくなります。リンターはこれを no-deprecated-control-renderer-declaration として検出し、「Control '...' is missing a renderer declaration」というメッセージを表示します。

最新化のワークフローは次のとおりです。デフォルトパスに <ControlName>Renderer モジュールが存在するかを確認し、存在する場合は sap.ui.define でインポートして、renderer プロパティに割り当てます。

修正方針

1. レンダラー宣言の欠落

問題:Control クラスにレンダラーが宣言されていません。

// Before - triggers no-deprecated-control-renderer-declaration
sap.ui.define([
    "sap/ui/core/Control"
], function(Control) {
    "use strict";

    return Control.extend("my.app.control.MyControl", {
        metadata: {
            properties: { ... }
        }
        // No renderer declaration!
    });
});

修正方法 A - レンダリングが不要な場合(Control が抽象クラスである、または子 Control を使用する場合):

// After - explicitly declare no renderer
sap.ui.define([
    "sap/ui/core/Control"
], function(Control) {
    "use strict";

    return Control.extend("my.app.control.MyControl", {
        metadata: {
            properties: { ... }
        },

        renderer: null
    });
});

修正方法 B - レンダラーが別ファイルにある場合(暗黙的な自動検出を含む):

UI5 1.x では、多くの Control がフレームワークの暗黙的な自動検出に依存しています。これらの Control には renderer プロパティがありませんが、既定のパスに <ControlName>Renderer.js ファイルが存在し、自動的に読み込まれます。この自動検出は最新の UI5 では廃止されているため、インポートを明示する必要があります。

レンダラーの見つけ方:

  1. レンダラーの想定パスを導きます。Control のモジュールパスに Renderer を追加します。たとえば、my/app/control/MyControl の場合は、my/app/control/MyControlRenderer を確認します。
  2. プロジェクト内でファイルを探します(例:Control と同じディレクトリにある MyControlRenderer.js)。
  3. レンダラーファイルがある場合は、インポートして割り当てます。ない場合は、修正方法 A(renderer: null)または修正方法 C(インラインレンダラー)を使用します。
// After - import and assign the renderer module
sap.ui.define([
    "sap/ui/core/Control",
    "./MyControlRenderer"
], function(Control, MyControlRenderer) {
    "use strict";

    return Control.extend("my.app.control.MyControl", {
        metadata: {
            properties: { ... }
        },

        renderer: MyControlRenderer
    });
});

重要:レンダラーをインポートした後、レンダラーモジュール自体に apiVersion: 2 が設定されているかも確認します。設定されていない場合は、別のリンター指摘事項です。下記のセクション 3「レンダラーでの apiVersion の欠落」を参照してください。

修正方法 C - インラインレンダラーを追加する:

// After - define renderer inline with apiVersion: 2
sap.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. 文字列によるレンダラー宣言

問題:レンダラーを文字列で宣言すると、同期読み込みが発生します。

// Before - triggers no-deprecated-control-renderer-declaration
sap.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!
    });
});

修正方法:レンダラーモジュールをインポートし、直接割り当てます。

// After - import renderer module
sap.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. レンダラーでの apiVersion の欠落

問題:レンダラーオブジェクトまたは関数に apiVersion の宣言がありません。

// Before - triggers no-deprecated-api
renderer: {
    render: function(oRm, oControl) {
        oRm.write("<div");
        oRm.writeControlData(oControl);
        oRm.write(">");
        oRm.write("</div>");
    }
}

// OR - function without apiVersion
renderer: function(oRm, oControl) {
    oRm.write("<div>");
    oRm.write("</div>");
}

修正方法:apiVersion: 2 を追加し、セマンティックレンダリング API に変換します。

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

apiVersion 1 から apiVersion 2 へのメソッド変換:

旧メソッド(apiVersion 1)新メソッド(apiVersion 2)
oRm.write("<tag")oRm.openStart("tag") または oRm.voidStart("tag")
oRm.write(">")oRm.openEnd() または oRm.voidEnd()
oRm.write("</tag>")oRm.close("tag")
oRm.write(text)oRm.text(text)
oRm.writeControlData(oCtrl)Control を第 2 引数として渡します:oRm.openStart("div", oControl)
oRm.addClass("cls")oRm.class("cls")
oRm.writeAttribute("name", val)oRm.attr("name", val)

例を含む変換表の完全版については、references/renderer-api-mapping.md を参照してください。

4. IconPool のインポートの欠落

問題:IconPool をインポートせずに oRm.icon() を使用しています。

// Before - triggers no-deprecated-api
sap.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");
            }
        }
    });
});

修正方法:インポートに IconPool を追加します。コード内で直接参照していなくても、インポートが必要です。

// After - IconPool imported
sap.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. 非推奨の rerender() オーバーライド

問題:UI5 1.121 以降では、rerender() メソッドをオーバーライドしても機能しません。

// Before - triggers no-deprecated-api
sap.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();
        }
    });
});

修正方法:レンダリング前の処理は onBeforeRendering() に、レンダリング後の処理は onAfterRendering() に移します。

// After - use lifecycle hooks instead
sap.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();
        }
    });
});

実装手順

  1. --details を指定してリンターを実行し、追加のコンテキストを取得します:

    npx @ui5/linter --details
    
  2. リンターの出力(ルール ID とメッセージ)からエラーパターンを特定します

  3. Control のレンダリング要件を確認します:

    • Control にカスタムレンダリングが必要ですか?
    • 既存の別レンダラーファイルはありますか?既定のパスを確認してください:同じディレクトリにある <ControlName>Renderer.js(UI5 1.x の自動検出パス)
    • レンダラーは oRm.icon() を使用していますか?
  4. 適切な変換を適用します:

    • 宣言がない場合:既定のパスに <ControlName>Renderer.js があるか(自動検出)確認します。ある場合はインポートして割り当てます。ない場合は renderer: null を追加するか、インラインレンダラーを作成します
    • 文字列による宣言の場合:モジュールのインポートに変換します
    • apiVersion がない場合:apiVersion: 2 を追加し、レンダリングメソッドを変換します
    • IconPool の場合:インポートを sap.ui.define の依存関係に追加します
    • rerender のオーバーライドの場合:処理をライフサイクルフックに移します
    • static でない場合:static キーワードを追加します(ES6 クラス)
  5. リンターを再実行して修正を確認します

修正セッションの例

リンターの出力が次の場合:

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

修正前:

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;
});

修正後:

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) - updated
sap.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;
});

注意事項

  • これらの基底クラスを拡張するコントロールでは、レンダラー宣言は不要です:

    • sap/ui/core/mvc/View
    • sap/ui/core/XMLComposite
    • sap/ui/core/webc/WebComponent
    • sap/uxap/BlockBase
  • apiVersion: 4 も有効で、最新の UI5 向けに追加の最適化が提供されます

  • apiVersion 1 から 2 に変換する場合は、すべての write() 呼び出しがセマンティックメソッドに適切に変換されていることを確認してください

  • アイコンフォントの登録には、モジュールの読み込み時に IconPool のインポートが必要です。コード内で IconPool 変数を使用しない場合も同様です

関連スキル

  • fix-js-globals:レンダラー以外の JavaScript ファイル(コントローラーやユーティリティなど)で no-globals エラーが発生した場合は、fix-js-globals を使用してください。sap.ui.define の依存関係の追加とグローバルアクセスの置き換えに対応します
  • fix-pseudo-modules:レンダラーコードに enum または DataType の擬似モジュールのインポートも含まれる場合は、それらの問題には fix-pseudo-modules を使用してください
  • fix-library-init:Library.init()/Lib.init() の apiVersion エラー(「Deprecated call to ... Use the {apiVersion: 2} parameter」)には、fix-library-init を使用してください。ライブラリの初期化に対応し、レンダラーオブジェクトは対象外です

コメント