App scripts v1.3.0 prod build removes custom decorators by default. We are using custom decorator on components to subscribe and unsubscribe from redux store.
Some way to be able to keep custom decotators. How can we turn off this optimization?
Which @ionic/app-scripts version are you using?
v1.3.0
Just about to post the exact same issue! We're using Angular Redux Store with @select decorator.
Using v1.3.0 breaks @select :(
I ran into this too, disabled purging of decorators to keep it working: https://forum.ionicframework.com/t/ionic-v3-white-screen-when-building-with-prod/85589/3?u=infoproducts
@biesbjerg that is exactly what I am looking for. Thanks
I'll resolve, we should only purge Ionic and Angular decorators.
Thanks,
Dan
Can one of you do me a favor and add a config node to package.json like this:
...
"config" : {
"ionic_aot_write_to_disk" : true
}
...
and then do npm run ionic:build --aot.
Then open ./.tmp/src/the/path/to/a/file/with/custom/decorators.js and paste the content of the file in here? I will add unit tests with the specific decorator content to ensure it works.
Thanks,
Dan
@danbucholtz Built using v1.3.0 without setting "ionic_purge_decorators": false in config. Is this what you were looking for?
Package.json
...
"config" : {
"ionic_aot_write_to_disk" : true
},
"devDependencies": {
"@ionic/app-scripts": "1.3.0",
"typescript": "2.2.1"
},
...
Original
import { Component } from '@angular/core';
import { select } from '@angular-redux/store';
import { IUserState } from './../../../reducers/user.reducer';
@Component({
selector: 'page-dash',
templateUrl: 'dash-page.html'
})
export class DashPage {
user: IUserState;
@select() user$;
constructor() {}
public ionViewDidLoad() :void {
this.user$.subscribe(user => {
this.user = user;
});
}
}
Result of npm run ionic:build --aot
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { Component } from '@angular/core';
import { select } from '@angular-redux/store';
var DashPage = (function () {
function DashPage() {
}
DashPage.prototype.ionViewDidLoad = function () {
var _this = this;
this.user$.subscribe(function (user) {
_this.user = user;
});
};
return DashPage;
}());
__decorate([
select(),
__metadata("design:type", Object)
], DashPage.prototype, "user$", void 0);
DashPage = __decorate([
Component({
selector: 'page-dash',
templateUrl: 'dash-page.html'
}),
__metadata("design:paramtypes", [])
], DashPage);
export { DashPage };
//# sourceMappingURL=dash-page.js.map
Yes, that is perfect, thank you
Keep 'em coming. Does anyone use a custom decorator on a class?
Thanks,
Dan
@danbucholtz Yes, we do. We use custom decorator on components (ionic pages). Decorator subcribes on redux store in ngOnInit hook and unsubscribes in ngOnDestroy.
@kesozjura,
Can you give me as many transpiled .js files as you can that look significantly different in their decorator configuration?
Thanks,
Dan
This is hopefully fixed in 1.3.1.
npm install @ionic/[email protected]
If this doesn't fix your issue, please follow my instructions above and upload a transpiled file. There are many different types of decorators so I want to make sure I am catching them all.
Thanks,
Dan
@danbucholtz
v 1.3.1 fixed the issue. Just for your info I posted sources anyway:
Original .ts:
import { Component, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { ToastController } from 'ionic-angular';
import { PageWithBriefcase } from '../page-with-briefcase';
import { Pm1MobileStore } from '../../store/pm1-mobile-store';
import { StateObserver } from '../../decorators/state-observer';
@Component({
templateUrl: 'performance.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
@StateObserver<PerformancePage>()
export class PerformancePage extends PageWithBriefcase {
constructor(public store: Pm1MobileStore, private _changeDetector: ChangeDetectorRef, private _toastController: ToastController) {
super();
}
onStateChanged = (state: State) => {
this.selectedBriefcase = state.briefcasesState.selectedBriefcase;
}
ngOnInit() { }
ngOnDestroy() { }
}
Transpiled .js in .tmp folder:
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { Component, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { ToastController } from 'ionic-angular';
import { PageWithBriefcase } from '../page-with-briefcase';
import { Pm1MobileStore } from '../../store/pm1-mobile-store';
import { StateObserver } from '../../decorators/state-observer';
var PerformancePage = (function (_super) {
__extends(PerformancePage, _super);
function PerformancePage(store, _changeDetector, _toastController) {
var _this = _super.call(this) || this;
_this.store = store;
_this._changeDetector = _changeDetector;
_this._toastController = _toastController;
_this.onStateChanged = function (state) {
_this.selectedBriefcase = state.briefcasesState.selectedBriefcase;
};
return _this;
}
PerformancePage.prototype.ngOnInit = function () { };
PerformancePage.prototype.ngOnDestroy = function () { };
return PerformancePage;
}(PageWithBriefcase));
PerformancePage = __decorate([
Component({
templateUrl: 'performance.html',
changeDetection: ChangeDetectionStrategy.OnPush
}),
StateObserver(),
__metadata("design:paramtypes", [typeof (_a = typeof Pm1MobileStore !== "undefined" && Pm1MobileStore) === "function" && _a || Object, typeof (_b = typeof ChangeDetectorRef !== "undefined" && ChangeDetectorRef) === "function" && _b || Object, typeof (_c = typeof ToastController !== "undefined" && ToastController) === "function" && _c || Object])
], PerformancePage);
export { PerformancePage };
var _a, _b, _c;
//# sourceMappingURL=performance.js.map
And custom decorator source:
export function StateObserver<T extends StateObserverComponent>() {
return function (target) {
target.prototype.ngOnInit = ngOnInitDecorator(target.prototype.ngOnInit);
function ngOnInitDecorator(originalNgOnInit) {
return function () {
let store: Pm1MobileStore = this.store;
let superData = originalNgOnInit ? originalNgOnInit.apply(this, arguments) : null;
this['__unsubscribe'] = store.subscribe(state => this.onStateChanged(state));
this.onStateChanged(store.getState());
return superData;
}
}
target.prototype.ngOnDestroy = ngOnDestroyDecorator(target.prototype.ngOnDestroy);
function ngOnDestroyDecorator(originalNgOnDestroy) {
return function () {
let superData = originalNgOnDestroy ? originalNgOnDestroy.apply(this, arguments) : null;
if (this['__unsubscribe']) {
this['__unsubscribe']();
this['__unsubscribe'] = undefined;
}
return superData;
}
}
return target;
}
}
Most helpful comment
This is hopefully fixed in
1.3.1.If this doesn't fix your issue, please follow my instructions above and upload a transpiled file. There are many different types of decorators so I want to make sure I am catching them all.
Thanks,
Dan