今日又係要講返 ExtJS 既野,話說 Webpack 已經流行左一大段時間,好多野都變得容易管理左好多。但係如果要將一個 Framework 搬去 Webpack 度用就實在係有啲困難,因為 Framework 通常都會用到好多好底層的功能。而呢啲功能本身既前題係運行個 Scope 有自己本身固定既 Context,運單啲講 Webpack 當 Bundle 完個 package 之後,入面所運行既 JS 係有自己個 Context,係同 Browser 入面 html embed 的 Javascript Context 唔一樣,會有可能引起 Webpack 打包後的 JS 運行唔到。 ### 自訂 ExtJS Component 如果你要自訂一個 Component,最起碼都要設定佢最基本既行為,例如當個 Component 建立時需要係 runtime 拎一啲 condition 來決定佢畫出來個樣。或者在建立後修改一下 child component 的數值等等。呢個時候如果睇官方個 Guide 係會教你可以用 `initComponent()` 去改寫 Component 生成時的行為,當中有一個 statement 係 `this.callParent()`。佢係類似 Java 入面 `super()` 的 method,用來叫返 override 左既 super class 個 method。正常用係無問題既,但係如果當你係魔改配合 Webpack 使用的話,就會出 Error。 睇下呢段 Code: ```js // 定義一個 component Ext.define('MyApp.view.YourComponent', { // extend 'Ext.window.Window' 呢個 component extend: 'Ext.window.Window', // 原本個 title title: 'foo', // 自動顯示 autoShow: true, // 用 initComponent 來改寫 initComponent: function(...args) { // 生成 component this.callParent(...args); // 改下個 title this.setTitle('bar'); }, }); // 生成 class Ext.create('MyApp.view.YourComponent'); ``` 之後就會出 Error : ```js Uncaught TypeError: Cannot read properties of null (reading '$owner') at constructor.callParent ``` ### 用 beforerender event 上網找左好耐好耐都找唔到有效既方法,後來用左 beforerender event 暫時頂住先,後來又改用 added event 來頂住,但係都只係治標不治本既方法。 使用 beforerender 來 workaround: ```js // 定義一個 component Ext.define('MyApp.view.YourComponent', { // extend 'Ext.window.Window' 呢個 component extend: 'Ext.window.Window', // 原本個 title title: 'foo', // 自動顯示 autoShow: true, // 設定 listeners listeners: { // beforerender 係生命週期比較早的 event beforerender: view => { // 改下個 title view.setTitle('bar') }, }, }); // 生成 class Ext.create('MyApp.view.YourComponent'); ``` ### Strict Mode 問題 其實 this.callParent() 係會用到 arguments.callee 同埋 arguments.caller 來配合達成到 call 返 override 的 method。 所以在 Strict Mode 底下會有機會用唔到 this.callParent()... ### Workaround 方法 之後睇到有一篇大神講 ExtJS + Webpack 的使用方法,入面提到如果要用 this.callParent() 的話需要使用到 class prototype 去完成,我再測試一下法現成功了! 實現方法如下: ```js // 定義一個 component Ext.define('MyApp.view.YourComponent', { // extend 'Ext.window.Window' 呢個 component extend: 'Ext.window.Window', // 原本個 title title: 'foo', // 自動顯示 autoShow: true, // 用 initComponent 來改寫 initComponent: function(...args) { // 生成 component // this.callParent(...args); // 會出 Error // workaround 方法, 主要係 call 返 extend component prototype 個 method, 再放返現在 context 個 this 入去 Ext.window.Window.prototype.initComponent.call(this, ...args); // 改下個 title this.setTitle('bar'); }, }); // 生成 class Ext.create('MyApp.view.YourComponent'); ``` 咁就可以成功啦 !