Browse Source

UI: Optimizations - AOT + JIT

pull/3911/head
Igor Kulikov 6 years ago
parent
commit
ddb3ee61e7
  1. 2
      ui-ngx/angular.json
  2. 29
      ui-ngx/extra-webpack.config.js
  3. 1
      ui-ngx/package.json
  4. 8
      ui-ngx/src/app/core/auth/auth.service.ts
  5. 59
      ui-ngx/src/app/core/services/dynamic-component-factory.service.ts
  6. 87
      ui-ngx/src/app/core/services/resources.service.ts
  7. 2
      ui-ngx/src/app/modules/home/components/filter/complex-filter-predicate.component.ts
  8. 2
      ui-ngx/src/app/modules/home/components/filter/filter-text.component.ts
  9. 2
      ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule-condition-dialog.component.ts
  10. 3
      ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog.component.ts
  11. 2
      ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts
  12. 5
      ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts
  13. 4
      ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts
  14. 2
      ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts
  15. 36
      ui-ngx/src/app/shared/components/json-form/json-form.component.ts
  16. 14
      ui-ngx/src/app/shared/components/led-light.component.ts

2
ui-ngx/angular.json

@ -22,6 +22,7 @@
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.app.json",
"aot": true,
"assets": [
"src/thingsboard.ico",
"src/assets",
@ -161,6 +162,7 @@
"serve": {
"builder": "@angular-builders/custom-webpack:dev-server",
"options": {
"aot": true,
"browserTarget": "thingsboard:build",
"proxyConfig": "proxy.conf.js"
},

29
ui-ngx/extra-webpack.config.js

@ -14,8 +14,10 @@
* limitations under the License.
*/
const CompressionPlugin = require("compression-webpack-plugin");
const TerserPlugin = require("terser-webpack-plugin");
const webpack = require("webpack");
const dirTree = require("directory-tree");
const AngularCompilerPlugin = require('@ngtools/webpack');
var langs = [];
@ -25,12 +27,14 @@ dirTree("./src/assets/locale/", {extensions: /\.json$/}, (item) => {
langs.push(item.name.slice(item.name.lastIndexOf("-") + 1, -5));
});
module.exports = {
plugins: [
module.exports = (config, options) => {
config.plugins.push(
new webpack.DefinePlugin({
TB_VERSION: JSON.stringify(require("./package.json").version),
SUPPORTED_LANGS: JSON.stringify(langs),
}),
})
);
config.plugins.push(
new CompressionPlugin({
filename: "[path][base].gz[query]",
algorithm: "gzip",
@ -38,6 +42,21 @@ module.exports = {
threshold: 10240,
minRatio: 0.8,
deleteOriginalAssets: false,
}),
],
})
);
if (config.mode === 'production') {
const index = config.plugins.findIndex(p => p instanceof AngularCompilerPlugin.AngularCompilerPlugin);
const angularCompilerOptions = config.plugins[index]._options;
angularCompilerOptions.emitClassMetadata = true;
angularCompilerOptions.emitNgModuleScope = true;
config.plugins.splice(index, 1);
config.plugins.push(new AngularCompilerPlugin.AngularCompilerPlugin(angularCompilerOptions));
const terserPluginOptions = config.optimization.minimizer[1].options;
delete terserPluginOptions.terserOptions.compress.global_defs.ngJitMode;
terserPluginOptions.terserOptions.compress.side_effects = false;
config.optimization.minimizer.splice(1, 1);
config.optimization.minimizer.push(new TerserPlugin(terserPluginOptions));
}
return config;
};

1
ui-ngx/package.json

@ -100,6 +100,7 @@
"@angular/cli": "^10.1.5",
"@angular/compiler-cli": "^10.1.5",
"@angular/language-service": "^10.1.5",
"@ngtools/webpack": "10.1.5",
"@types/canvas-gauges": "^2.1.2",
"@types/flot": "^0.0.31",
"@types/jasmine": "^3.5.12",

8
ui-ngx/src/app/core/auth/auth.service.ts

@ -446,8 +446,12 @@ export class AuthService {
const refreshTokenValid = AuthService.isTokenValid('refresh_token');
this.setUserFromJwtToken(null, null, false);
if (!refreshTokenValid) {
this.refreshTokenSubject.error(new Error(this.translate.instant('access.refresh-token-expired')));
this.refreshTokenSubject = null;
this.translate.get('access.refresh-token-expired').subscribe(
(translation) => {
this.refreshTokenSubject.error(new Error(translation));
this.refreshTokenSubject = null;
}
);
} else {
const refreshTokenRequest = {
refreshToken

59
ui-ngx/src/app/core/services/dynamic-component-factory.service.ts

@ -59,37 +59,40 @@ export class DynamicComponentFactoryService {
template: string,
modules?: Type<any>[]): Observable<ComponentFactory<T>> {
const dymamicComponentFactorySubject = new ReplaySubject<ComponentFactory<T>>();
const comp = this.createDynamicComponent(componentType, template);
let moduleImports: Type<any>[] = [CommonModule];
if (modules) {
moduleImports = [...moduleImports, ...modules];
}
// noinspection AngularInvalidImportedOrDeclaredSymbol
@NgModule({
declarations: [comp],
imports: moduleImports
})
class DynamicComponentInstanceModule extends DynamicComponentModule {}
try {
this.compiler.compileModuleAsync(DynamicComponentInstanceModule).then(
(module) => {
const moduleRef = module.create(this.injector);
const factory = moduleRef.componentFactoryResolver.resolveComponentFactory(comp);
this.dynamicComponentModulesMap.set(factory, {
moduleRef,
moduleType: module.moduleType
});
dymamicComponentFactorySubject.next(factory);
dymamicComponentFactorySubject.complete();
import('@angular/compiler').then(
() => {
const comp = this.createDynamicComponent(componentType, template);
let moduleImports: Type<any>[] = [CommonModule];
if (modules) {
moduleImports = [...moduleImports, ...modules];
}
).catch(
(e) => {
// noinspection AngularInvalidImportedOrDeclaredSymbol
const dynamicComponentInstanceModule = NgModule({
declarations: [comp],
imports: moduleImports
})(class DynamicComponentInstanceModule extends DynamicComponentModule {});
try {
this.compiler.compileModuleAsync(dynamicComponentInstanceModule).then(
(module) => {
const moduleRef = module.create(this.injector);
const factory = moduleRef.componentFactoryResolver.resolveComponentFactory(comp);
this.dynamicComponentModulesMap.set(factory, {
moduleRef,
moduleType: module.moduleType
});
dymamicComponentFactorySubject.next(factory);
dymamicComponentFactorySubject.complete();
}
).catch(
(e) => {
dymamicComponentFactorySubject.error(e);
}
);
} catch (e) {
dymamicComponentFactorySubject.error(e);
}
);
} catch (e) {
dymamicComponentFactorySubject.error(e);
}
}
);
return dymamicComponentFactorySubject.asObservable();
}

87
ui-ngx/src/app/core/services/resources.service.ts

@ -78,28 +78,31 @@ export class ResourcesService {
(module) => {
const modules = this.extractNgModules(module);
if (modules.length) {
const tasks: Promise<ModuleWithComponentFactories<any>>[] = [];
for (const m of modules) {
tasks.push(this.compiler.compileModuleAndAllComponentsAsync(m));
}
forkJoin(tasks).subscribe((compiled) => {
try {
const componentFactories: ComponentFactory<any>[] = [];
for (const c of compiled) {
c.ngModuleFactory.create(this.injector);
componentFactories.push(...c.componentFactories);
import('@angular/compiler').then(
() => {
const tasks: Promise<ModuleWithComponentFactories<any>>[] = [];
for (const m of modules) {
tasks.push(this.compiler.compileModuleAndAllComponentsAsync(m));
}
this.loadedFactories[url].next(componentFactories);
this.loadedFactories[url].complete();
} catch (e) {
this.loadedFactories[url].error(new Error(`Unable to init module from url: ${url}`));
delete this.loadedFactories[url];
}
},
(e) => {
this.loadedFactories[url].error(new Error(`Unable to compile module from url: ${url}`));
delete this.loadedFactories[url];
});
forkJoin(tasks).subscribe((compiled) => {
try {
const componentFactories: ComponentFactory<any>[] = [];
for (const c of compiled) {
c.ngModuleFactory.create(this.injector);
componentFactories.push(...c.componentFactories);
}
this.loadedFactories[url].next(componentFactories);
this.loadedFactories[url].complete();
} catch (e) {
this.loadedFactories[url].error(new Error(`Unable to init module from url: ${url}`));
delete this.loadedFactories[url];
}
},
(e) => {
this.loadedFactories[url].error(new Error(`Unable to compile module from url: ${url}`));
delete this.loadedFactories[url];
}); }
);
} else {
this.loadedFactories[url].error(new Error(`Module '${url}' doesn't have default export!`));
delete this.loadedFactories[url];
@ -133,26 +136,30 @@ export class ResourcesService {
} catch (e) {
}
if (modules && modules.length) {
const tasks: Promise<ModuleWithComponentFactories<any>>[] = [];
for (const m of modules) {
tasks.push(this.compiler.compileModuleAndAllComponentsAsync(m));
}
forkJoin(tasks).subscribe((compiled) => {
try {
for (const c of compiled) {
c.ngModuleFactory.create(this.injector);
}
this.loadedModules[url].next(modules);
this.loadedModules[url].complete();
} catch (e) {
this.loadedModules[url].error(new Error(`Unable to init module from url: ${url}`));
delete this.loadedModules[url];
import('@angular/compiler').then(
() => {
const tasks: Promise<ModuleWithComponentFactories<any>>[] = [];
for (const m of modules) {
tasks.push(this.compiler.compileModuleAndAllComponentsAsync(m));
}
},
(e) => {
this.loadedModules[url].error(new Error(`Unable to compile module from url: ${url}`));
delete this.loadedModules[url];
});
forkJoin(tasks).subscribe((compiled) => {
try {
for (const c of compiled) {
c.ngModuleFactory.create(this.injector);
}
this.loadedModules[url].next(modules);
this.loadedModules[url].complete();
} catch (e) {
this.loadedModules[url].error(new Error(`Unable to init module from url: ${url}`));
delete this.loadedModules[url];
}
},
(e) => {
this.loadedModules[url].error(new Error(`Unable to compile module from url: ${url}`));
delete this.loadedModules[url];
});
}
);
} else {
this.loadedModules[url].error(new Error(`Module '${url}' doesn't have default export or not NgModule!`));
delete this.loadedModules[url];

2
ui-ngx/src/app/modules/home/components/filter/complex-filter-predicate.component.ts

@ -77,7 +77,7 @@ export class ComplexFilterPredicateComponent implements ControlValueAccessor, On
this.complexFilterPredicate = predicate;
}
private openComplexFilterDialog() {
public openComplexFilterDialog() {
this.dialog.open<ComplexFilterPredicateDialogComponent, ComplexFilterPredicateDialogData,
ComplexFilterPredicateInfo>(ComplexFilterPredicateDialogComponent, {
disableClose: true,

2
ui-ngx/src/app/modules/home/components/filter/filter-text.component.ts

@ -59,7 +59,7 @@ export class FilterTextComponent implements ControlValueAccessor, OnInit {
requiredClass = false;
private filterText: string;
public filterText: string;
private propagateChange = (v: any) => { };

2
ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule-condition-dialog.component.ts

@ -38,7 +38,7 @@ export interface AlarmRuleConditionDialogData {
selector: 'tb-alarm-rule-condition-dialog',
templateUrl: './alarm-rule-condition-dialog.component.html',
providers: [{provide: ErrorStateMatcher, useExisting: AlarmRuleConditionDialogComponent}],
styleUrls: ['/alarm-rule-condition-dialog.component.scss']
styleUrls: ['./alarm-rule-condition-dialog.component.scss']
})
export class AlarmRuleConditionDialogComponent extends DialogComponent<AlarmRuleConditionDialogComponent, AlarmCondition>
implements OnInit, ErrorStateMatcher {

3
ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog.component.ts

@ -15,7 +15,7 @@
///
import { MatDialogRef } from '@angular/material/dialog';
import { Inject, InjectionToken } from '@angular/core';
import { Directive, Inject, InjectionToken } from '@angular/core';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { Router } from '@angular/router';
@ -30,6 +30,7 @@ export interface CustomDialogData {
[key: string]: any;
}
@Directive()
export class CustomDialogComponent extends PageComponent {
[key: string]: any;

2
ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts

@ -154,7 +154,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
private alarmsTitlePattern: string;
private displayDetails = true;
private allowAcknowledgment = true;
public allowAcknowledgment = true;
private allowClear = true;
private defaultPageSize = 10;

5
ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts

@ -186,11 +186,16 @@ export type TripAnimationSettings = {
usePointAsAnchor: boolean;
normalizationStep: number;
showPolygon: boolean;
showLabel: boolean;
showTooltip: boolean;
latKeyName: string;
lngKeyName: string;
rotationAngle: number;
label: string;
tooltipPattern: string;
tooltipColor: string;
tooltipOpacity: number;
tooltipFontColor: string;
useTooltipFunction: boolean;
useLabelFunction: boolean;
pointAsAnchorFunction: GenericFunction;

4
ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts

@ -102,11 +102,11 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni
ctx: WidgetContext;
private formResize$: ResizeObserver;
private settings: MultipleInputWidgetSettings;
public settings: MultipleInputWidgetSettings;
private widgetConfig: WidgetConfig;
private subscription: IWidgetSubscription;
private datasources: Array<Datasource>;
private sources: Array<MultipleInputWidgetSource> = [];
public sources: Array<MultipleInputWidgetSource> = [];
isVerticalAlignment: boolean;
inputWidthSettings: string;

2
ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts

@ -126,7 +126,7 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI
private defaultPageSize = 10;
private defaultSortOrder = '-0';
private hideEmptyLines = false;
private showTimestamp = true;
public showTimestamp = true;
private dateFormatFilter: string;
private searchAction: WidgetAction = {

36
ui-ngx/src/app/shared/components/json-form/json-form.component.ts

@ -36,12 +36,14 @@ import { JsonFormProps } from './react/json-form.models';
import inspector from 'schema-inspector';
import * as tinycolor_ from 'tinycolor2';
import { DialogService } from '@app/core/services/dialog.service';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import ReactSchemaForm from './react/json-form-react';
// import * as React from 'react';
// import * as ReactDOM from 'react-dom';
// import ReactSchemaForm from './react/json-form-react';
import JsonFormUtils from './react/json-form-utils';
import { JsonFormComponentData } from './json-form-component.models';
import { GroupInfo } from '@shared/models/widget.models';
import { Observable } from 'rxjs/internal/Observable';
import { forkJoin, from } from 'rxjs';
const tinycolor = tinycolor_;
@ -252,11 +254,35 @@ export class JsonFormComponent implements OnInit, ControlValueAccessor, Validato
if (destroy) {
this.destroyReactSchemaForm();
}
ReactDOM.render(React.createElement(ReactSchemaForm, this.formProps), this.reactRootElmRef.nativeElement);
// import ReactSchemaForm from './react/json-form-react';
const reactSchemaFormObservables: Observable<any>[] = [];
reactSchemaFormObservables.push(from(import('react')));
reactSchemaFormObservables.push(from(import('react-dom')));
reactSchemaFormObservables.push(from(import('./react/json-form-react')));
forkJoin(reactSchemaFormObservables).subscribe(
(modules) => {
const react = modules[0];
const reactDom = modules[1];
const jsonFormReact = modules[2].default;
reactDom.render(react.createElement(jsonFormReact, this.formProps), this.reactRootElmRef.nativeElement);
}
);
/* import('./react/json-form-react').then(
(mod) => {
ReactDOM.render(React.createElement(mod.default, this.formProps), this.reactRootElmRef.nativeElement);
}
);*/
// ReactDOM.render(React.createElement(ReactSchemaForm, this.formProps), this.reactRootElmRef.nativeElement);
}
private destroyReactSchemaForm() {
ReactDOM.unmountComponentAtNode(this.reactRootElmRef.nativeElement);
import('react-dom').then(
(reactDom) => {
reactDom.unmountComponentAtNode(this.reactRootElmRef.nativeElement);
}
);
// ReactDOM.unmountComponentAtNode(this.reactRootElmRef.nativeElement);
}
private validateModel(): boolean {

14
ui-ngx/src/app/shared/components/led-light.component.ts

@ -16,7 +16,7 @@
import { AfterViewInit, Component, ElementRef, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import Raphael, { RaphaelElement, RaphaelPaper, RaphaelSet } from 'raphael';
import { RaphaelElement, RaphaelPaper, RaphaelSet } from 'raphael';
import * as tinycolor_ from 'tinycolor2';
const tinycolor = tinycolor_;
@ -90,10 +90,14 @@ export class LedLightComponent implements OnInit, AfterViewInit, OnChanges {
if (this.paper) {
this.paper.remove();
}
this.paper = Raphael($('#canvas_container', this.elementRef.nativeElement)[0], this.canvasSize, this.canvasSize);
const center = this.canvasSize / 2;
this.circleElement = this.paper.circle(center, center, this.radius);
this.draw();
import('raphael').then(
(raphael) => {
this.paper = raphael.default($('#canvas_container', this.elementRef.nativeElement)[0], this.canvasSize, this.canvasSize);
const center = this.canvasSize / 2;
this.circleElement = this.paper.circle(center, center, this.radius);
this.draw();
}
);
}
private draw() {

Loading…
Cancel
Save