HOME > 開発者向けBLOG > Sencha Blog >  Ext JS 3.4 アプリをExt JS 6 にアップグレードする方法

Technology Note 開発者向けBLOG

Sencha Blog

Ext JS 3.4 アプリをExt JS 6 にアップグレードする方法

こんにちは、ゼノフィseoです。

この記事は、US Sencha社ブログ How to Upgrade Your Ext JS 3.4 Apps to Ext JS 6(2016年3月30日|Olga Petrova)を翻訳したものです

Ext JS は機能面において非常に成熟したフレームワークです。2007年に最初にリリースして以来、莫大な数の強力な機能を追加してきました。フレームワークのそれぞれのバージョンを通して何千というアプリケーションが作られており、そのうち成功しているプロジェクトのいくつかはまだExt JS 3.4 を利用しています。

プロジェクトを最新版にマイグレーションして最新の機能を活用したいにもかかわらず、その手順がわからないという開発者の方はいます。マイグレーションをまだしない理由として多くの理由は同様です。開発したアプリケーションは安定しており、バグは全て取り除かれ、すべてが問題なく動作しています。また同時に、そのアプリケーションは複雑であり、カスタムコンポーネントやエクステンションを多数抱えているためにマイグレーションは簡単でないと感じているのです。

一方、Ext JS 6 へのアップグレードに関してほとんどの開発者は同じメリットを挙げています:

  • ブラウザのアップデートをコントロールする必要がない
  • アプリケーションのメンテナンスの時間と労力を減少できる
  • パフォーマンスとメモリの使用を改善できる
  • モバイル端末とタッチイベントに対するサポートを活用できる
  • 数行のコードでを書くだけでExt JSの新機能を利用できる

お客様には常に、フレームワークの最新版Ext JS 6 へのアップグレードをお奨めしています。

この記事では簡単なマイグレーションの例をお見せします。実例としてExt JS 3.4 のグリッドをExt JS 6 にマイグレートしました。オリジナルと最終的なソースコードはレビューしていただけるようにしました。

オリジナル:
How to Upgrade Your Ext JS 3.4 Apps to Ext JS 6

マイグレーション後:
How to Upgrade Your Ext JS 3.4 Apps to Ext JS 6

Ext JS 6 アプリケーションはMVVM(Model-View-ViewModel)アーキテクチャパターンをベースにビルドします。MVVMにはView(ViewModel)という概念があり、これによりModelのデータと、Viewにおけるそのデータ表現(例えばデータバインディング)の間の変更を管理します。MVVMパターンについて詳しくはこちらをお読みください。

空のExt JS 6 プロジェクトを新規に生成する

コマンドラインツールであるSencha Cmdを使用して空のExt JS 6 プロジェクトを生成することができます。Ext JS 6 SDK フォルダまでコマンドラインもしくはターミナルで移動し、次のコマンドを実行します:

sencha generate app -classic -starter=false Migration ../migration

Sencha Cmdの機能について詳しくはこちらをお読みください 。

新規プロジェクトを初期化する

空のプロジェクトにApplicationクラス、およびMain Viewクラスを追加する必要があります。これらのクラスはアプリケーションを実行する上で必要です。

  1. メインビューも同様にSencha Cmdで生成することができます。新規に作成したマイグレーションフォルダに移動し、以下のコマンドを実行します:
  2. sencha generate view main.Main
  3. Applicationクラスは手動で生成します。app/Application.jsファイルを下記の内容で作成します:
  4. Ext.define('Migration.Application', {
        extend: 'Ext.app.Application',
        name: 'Migration'
    });
  5. 最後に、Ext JS 6 アプリケーションをビルドし、内部のウェブサーバを利用して実行します。次のコマンドをmigrationフォルダから実行します:
  6. sencha app build
    sencha web start
  7. ブラウザでhttp://localhost:1841/ に移動し、アプリケーションが実行されていることを確かめます。以下のような画面が確認できるかと思います:

How to Upgrade Your Ext JS 3.4 Apps to Ext JS 6

Modelをマイグレートする

ここからExt JS 3.4 コードを新しいExt JS 6 プロジェクトにマイグレートすることができます。まずはModelをマイグレートします。アプリケーションで使用されているデータフォーマットをModelで表現します。データのフォーマットはExt JS 3.4 ではストア定義の中で、フィールドプロパティにより定義します。

var store = new Ext.data.ArrayStore({
    fields: [
        {name: 'company'},
        {name: 'price',      type: 'float'},
        {name: 'change',     type: 'float'},
        {name: 'pctChange',  type: 'float'},
        {name: 'lastChange', type: 'date', dateFormat: 'n/j h:ia'}
    ]
});

これは後方互換性の定義であるため、Ext JS 6 を含む上位バージョンでも同じ方法でデータフォーマットを定義することができます。しかしModelクラスで分離して定義する方が適切で、このクラスではデータに紐づくフィールドやその他のロジックを定義します。

  1. Modelクラスを作成します
    1. app/model/Company.jsファイルを下記の内容で作成します:
    2. Ext.define('Migration.model.Company', {
              extend: 'Ext.data.Model'
      });
    3. Ext JS 3.4 のストアからフィールドプロパティをモデルにコピーします:
    4. Ext.define('Migration.model.Company', {
          extend: 'Ext.data.Model',
          fields: [
              {name: 'company'},
              {name: 'price',      type: 'float'},
              {name: 'change',     type: 'float'},
              {name: 'pctChange',  type: 'float'},
              {name: 'lastChange', type: 'date', dateFormat: 'n/j h:ia'}
          ]
      });

      Storeは基本的にExt JS 3.4 と同じで、レコード(Modelクラスのインスタンス)の集合です。

  2. Storeクラスを作成します
    1. app/store/Company.jsファイルを下記の内容で作成します:
    2. Ext.define('Migration.store.Companies', {
          extend: 'Ext.data.ArrayStore',
          alias: 'store.companies' 
      });
    3. Storeクラスには新規に作成したModelを使用します:
    4. Ext.define('Migration.store.Companies', {
          extend: 'Ext.data.ArrayStore',
          alias: 'store.companies',
          requires: ['Migration.model.Company'],
          model: 'Migration.model.Company'
      });

Viewをマイグレートする

Grid Panelの基本的な扱い方はExt JS 3.4 と同一です。主な違いは今回はGrid Panelを分離してView Classに定義する必要があるという点です。

  1. まずView Classの空のテンプレートをGrid Panel用に作る必要があります。次のコマンドをマイグレーションフォルダから実行します:
  2. sencha generate view company.Grid
  3. app/view/company/Grid.jsファイルを編集します:
    1. Ext.grid.Panelにベースクラスをセットします(Ext JS 3.4 の場合のようにExt.grid.GridPanelではありません:
      extend: “Ext.grid.Panel”
    2. xtype: ‘companygrid’プロパティを追加します。これはGrid Panelへのリファレンスで、後ほど使用します
    3. htmlプロパティを取り除きます
  4. 新規に作成したGrid Viewに、Ext JS 3.4 のグリッドカラム定義およびその他のグリッドパネルのプロパティをコピーし、すべてのファンクションをひとまずコメントアウトします(それらは後ほどマイグレートします)。
  5. autoExpandColumn: ‘company’コンフィグを取り除き、flex: 1コンフィグをCompanyカラムに追加します。flexプロパティはカラム幅を管理するための新しい定義です。Ext.Component-cfg-flexについて詳しくはこちらをお読みください 。
  6. アクションカラムのiconプロパティおよびgetClassプロパティを、FontAwesomeアイコンへのリファレンスを持ったiconClsに変更します。
  7. 上記の手順を終えると、コードはこのような具合になっていると思います:

    Ext.define("Migration.view.company.Grid",{
        extend: "Ext.grid.Panel",
     
        requires: [
            "Migration.view.company.GridController",
            "Migration.view.company.GridModel"
        ],
     
        controller: "company-grid",
        viewModel: {
             type: "company-grid"
         },    
     
        columns: [
            {
                id       :'company',
                header   : 'Company',
                width    : 160,
                sortable : true,
                dataIndex: 'company',
                flex: 1
            },
            {
                header   : 'Price',
                width    : 75,
                sortable : true,
                //renderer : 'usMoney',
                dataIndex: 'price'
            },
            {
                header   : 'Change',
                width    : 75,
                sortable : true,
                //renderer : change,
                dataIndex: 'change'
            },
            {
                header   : '% Change',
                width    : 75,
                sortable : true,
                //renderer : pctChange,
                dataIndex: 'pctChange'
            },
            {
                header   : 'Last Updated',
                width    : 85,
                sortable : true,
                //renderer : Ext.util.Format.dateRenderer('m/d/Y'),
                dataIndex: 'lastChange'
            },
            {
                xtype: 'actioncolumn',
                width: 50,
                items: [{
                    iconCls: 'x-fa fa-minus',
                    tooltip: 'Sell stock'/*,
                    handler: function(grid, rowIndex, colIndex) {
                        var rec = store.getAt(rowIndex);
                        alert("Sell " + rec.get('company'));
                    }*/
                }, {
                    iconCls: 'x-fa fa-plus',
        /*
                    handler: function(grid, rowIndex, colIndex) {
                        var rec = store.getAt(rowIndex);
                        alert("Buy " + rec.get('company'));
                    }*/
                }]
            }
        ],
        stripeRows: true,
        height: 350,
        width: 600,
        title: 'Array Grid',
        stateful: true,
        stateId: 'grid'
    });
  8. ここで、Main ViewにGridを加える必要があります。Main ViewはExt.panel.Panelのインスタンスであり、Main Viewのitemsアレイ(先ほど定義したxtypeを使用します)、およびrequiresアレイ(クラス名を使用します)にGridを追加するだけで済みます:
  9. Ext.define("Migration.view.main.Main",{
        extend: "Ext.panel.Panel",
     
        requires: [
            "Migration.view.main.MainController",
            "Migration.view.main.MainModel",
            "Migration.view.company.Grid"
        ],
     
        controller: "main-main",
        viewModel: {
            type: "main-main"
        },
     
        items: [{
            xtype: 'companygrid'
        }]
    });
  10. 次のコマンドをマイグレーションフォルダから実行します:
  11. sencha app build
    sencha web start
  12. ブラウザでhttp://localhost:1841/ に移動し、アプリケーションが実行されていることを確かめます。以下のような画面が確認できるかと思います:

How to Upgrade Your Ext JS 3.4 Apps to Ext JS 6

ViewModelを作成する

ViewModelはExt JS 5 で導入された新しい概念です。Viewと、それに紐づけられたDataの間の変更を管理します。Sencha Cmdを使用してGrid Viewを生成すると、ViewModelクラスも同時に生成されます。

  1. ViewModelファイルであるapp/view/main/GridModel.jsを編集します:
    1. ViewModelクラスよりdataプロパティを取り除きます
    2. ViewModelクラスのstoresコンフィグにcompaniesストアを加えます
    3. companiesストアのdataコンフィグを、Ext JS 3.4 コードからもってきたデータにアサインします
    Ext.define('Migration.view.company.GridModel', {
         extend: 'Ext.app.ViewModel',
         alias: 'viewmodel.company-grid',
         requires: [
              "Migration.store.Companies"
         ],
     
         stores: {
           companies : {
             type: 'companies',
             data: [
                     ['3m Co', 71.72, 0.02,  0.03,  '9/1 12:00am'],
                     ['Alcoa Inc', 29.01, 0.42,  1.47,  '9/1 12:00am'],]
           }
         }
     
    });
  2. ViewModelにGridをバインドします
  3. Grid Viewにbindコンフィグを追加し、ViewModelのcompaniesストアにグリッドをバインドします:

    bind: {
         store: '{companies}'
    },

ViewControllewにコードをマイグレートする

ViewControllerもMVVMパターンの一部です。Viewに対してそれぞれViewControllerが個別に作成されます。ViewControllerはイベントをリッスンし、アプリケーションのビジネスロジックを実行します。今回の場合、先ほどコメントアウトした機能をViewControllerに移します。ViewControllerはactioncolumnのaddボタンおよびdeleteボタンやカラムrendreresのハンドラを持ちます。Gid ViewのViewControllerもまたSencha Cmdにより生成されます。

  1. Ext JS 3.4 のchangeファンクションをGridController.jsファイルに移し、columnRendererにリネームします
  2. Ext JS 3.4 のpctChangeファンクションをGridController.jsファイルに移し、 pctColumnRendererにリネームします
  3. actioncolumnの削除ボタンのhandlerファンクションをGridController.jsに移動し、sellStockにリネームします。コード内のストアへのレファレンスをgrid.getStore()に変更します。
  4. actioncolumnの追加ボタンのhandlerファンクションをGridController.jsに移動し、buyStockにリネームします。コード内のストアへのレファレンスをgrid.getStore()に変更します。
  5. 上記の手順を終えると、GridController.jsはこのような具合になっていると思います:

    Ext.define('Migration.view.company.GridController', {
        extend: 'Ext.app.ViewController',
        alias: 'controller.company-grid',
     
        columnRenderer : function(val) {
            if (val > 0) {
                return '<span style="color:green;">' + val + '</span>';
            } else if (val < 0) {
                return '<span style="color:red;">' + val + '</span>';
            }
            return val;
        },
     
        pctColumnRenderer : function (val) {
            if (val > 0) {
                return '<span style="color:green;">' + val + '%</span>';
            } else if (val < 0) {
                return '<span style="color:red;">' + val + '%</span>';
            }
            return val;
        },
     
        sellStock: function(grid, rowIndex, colIndex) {
            var rec = grid.getStore().getAt(rowIndex);
            alert("Sell " + rec.get('company'));
        },
     
        buyStock: function(grid, rowIndex, colIndex) {
            var rec = grid.getStore().getAt(rowIndex);
            alert("Buy " + rec.get('company'));
        }
     
    });
  6. Gid View内の当該機能へのリファレンスを加え、renderer: ‘usMoney’renderer: Ext.util.Format.usMoneyに置き換えます:
  7. Ext.define("Migration.view.company.Grid",{
        extend: "Ext.grid.Panel",
     
        requires: [
            "Migration.view.company.GridController",
            "Migration.view.company.GridModel"
        ],
     
        xtype: 'companygrid',
     
        controller: "company-grid",
        viewModel: {
            type: "company-grid"
        },
     
        bind: {
            store: '{companies}'
        },
     
        columns: [
            {
                id       :'company',
                header   : 'Company',
                flex    : 1,
                sortable : true,
                dataIndex: 'company'
            },
            {
                header   : 'Price',
                width    : 75,
                sortable : true,
                renderer : Ext.util.Format.usMoney,
                dataIndex: 'price'
            },
            {
                header   : 'Change',
                width    : 75,
                sortable : true,
                renderer : 'columnRenderer',
                dataIndex: 'change'
            },
            {
                header   : '% Change',
                width    : 75,
                sortable : true,
                renderer : 'pctColumnRenderer',  
                dataIndex: 'pctChange'
            },
            {
                header   : 'Last Updated',
                width    : 85,
                sortable : true,
                renderer : Ext.util.Format.dateRenderer('m/d/Y'),
                dataIndex: 'lastChange'
            },
            {
                xtype: 'actioncolumn',
                width: 50,
                items: [{
                    iconCls: 'x-fa fa-minus',
                    tooltip: 'Sell stock',
                    handler: 'sellStock' 
                }, {
                    iconCls: 'x-fa fa-plus',
                    handler: 'buyStock'
                }
                ]
            }
        ],
     
        stripeRows: true,
        height: 350,
        width: 600,
        title: 'Array Grid',
        stateful: true,
        stateId: 'grid'
    });
  8. ブラウザでhttp://localhost:1841/ に移動し、アプリケーションが実行されていることを確かめます。以下のような画面が確認できるかと思います:

How to Upgrade Your Ext JS 3.4 Apps to Ext JS 6

まとめ

このガイドはExt JS 3.4 からExt JS 6 にマイグレートするためのサンプルです。詳しくはアップグレードガイドに記載しています (英語):

PAGETOP