Browse Source

Merge pull request #1858 from abpframework/feature/bundle-size

Feature/bundle size
pull/1873/head
Yasin Aydın 7 years ago
committed by GitHub
parent
commit
be1433846e
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      npm/ng-packs/.gitignore
  2. 25
      npm/ng-packs/angular.json
  3. 18
      npm/ng-packs/apps/dev-app/src/app/app.component.ts
  4. 14
      npm/ng-packs/packages/core/src/lib/models/application-configuration.ts
  5. 86
      npm/ng-packs/packages/core/src/lib/services/lazy-load.service.ts
  6. 35
      npm/ng-packs/packages/core/src/lib/states/config.state.ts
  7. 2
      npm/ng-packs/packages/theme-basic/src/lib/components/layout/layout.component.html
  8. 9
      npm/ng-packs/packages/theme-shared/src/lib/animations/slide.animations.ts
  9. 9
      npm/ng-packs/packages/theme-shared/src/lib/components/button/button.component.ts
  10. 2
      npm/ng-packs/packages/theme-shared/src/lib/contants/styles.ts
  11. 18
      npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts
  12. 52
      templates/app/angular/angular.json
  13. 18
      templates/app/angular/src/app/app.component.ts

1
npm/ng-packs/.gitignore

@ -3,6 +3,7 @@
# compiled output # compiled output
/tmp /tmp
/out-tsc /out-tsc
/dist/dev-app
# Only exists if Bazel was run # Only exists if Bazel was run
/bazel-out /bazel-out

25
npm/ng-packs/angular.json

@ -434,13 +434,30 @@
"tsConfig": "apps/dev-app/tsconfig.app.json", "tsConfig": "apps/dev-app/tsconfig.app.json",
"aot": false, "aot": false,
"assets": ["apps/dev-app/src/favicon.ico", "apps/dev-app/src/assets"], "assets": ["apps/dev-app/src/favicon.ico", "apps/dev-app/src/assets"],
"extractCss": true,
"styles": [ "styles": [
"apps/dev-app/src/styles.scss", "apps/dev-app/src/styles.scss",
"node_modules/bootstrap/dist/css/bootstrap.min.css", "node_modules/bootstrap/dist/css/bootstrap.min.css",
"node_modules/font-awesome/css/font-awesome.min.css", {
"node_modules/primeng/resources/themes/nova-light/theme.css", "input": "node_modules/font-awesome/css/font-awesome.min.css",
"node_modules/primeicons/primeicons.css", "lazy": true,
"node_modules/primeng/resources/primeng.min.css" "bundleName": "font-awesome.min"
},
{
"input": "node_modules/primeng/resources/themes/nova-light/theme.css",
"lazy": true,
"bundleName": "primeng-nova-light-theme"
},
{
"input": "node_modules/primeicons/primeicons.css",
"lazy": true,
"bundleName": "primeicons"
},
{
"input": "node_modules/primeng/resources/primeng.min.css",
"lazy": true,
"bundleName": "primeng.min"
}
], ],
"scripts": [] "scripts": []
}, },

18
npm/ng-packs/apps/dev-app/src/app/app.component.ts

@ -1,4 +1,5 @@
import { Component } from '@angular/core'; import { LazyLoadService } from '@abp/ng.core';
import { Component, OnInit } from '@angular/core';
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
@ -7,4 +8,17 @@ import { Component } from '@angular/core';
<router-outlet></router-outlet> <router-outlet></router-outlet>
`, `,
}) })
export class AppComponent {} export class AppComponent implements OnInit {
constructor(private lazyLoadService: LazyLoadService) {}
ngOnInit() {
this.lazyLoadService
.load(
['primeng.min.css', 'primeicons.css', 'primeng-nova-light-theme.css', 'font-awesome.min.css'],
'style',
null,
'head',
)
.subscribe();
}
}

14
npm/ng-packs/packages/core/src/lib/models/application-configuration.ts

@ -1,10 +1,12 @@
import { ABP } from './common';
export namespace ApplicationConfiguration { export namespace ApplicationConfiguration {
export interface Response { export interface Response {
localization: Localization; localization: Localization;
auth: Auth; auth: Auth;
setting: Setting; setting: Value;
currentUser: CurrentUser; currentUser: CurrentUser;
features: Features; features: Value;
} }
export interface Localization { export interface Localization {
@ -32,8 +34,8 @@ export namespace ApplicationConfiguration {
[key: string]: boolean; [key: string]: boolean;
} }
export interface Setting { export interface Value {
values: { [key: string]: 'Abp.Localization.DefaultLanguage' }; values: ABP.Dictionary<string>;
} }
export interface CurrentUser { export interface CurrentUser {
@ -42,8 +44,4 @@ export namespace ApplicationConfiguration {
tenantId: string; tenantId: string;
userName: string; userName: string;
} }
export interface Features {
values: Setting;
}
} }

86
npm/ng-packs/packages/core/src/lib/services/lazy-load.service.ts

@ -9,50 +9,68 @@ export class LazyLoadService {
loadedLibraries: { [url: string]: ReplaySubject<void> } = {}; loadedLibraries: { [url: string]: ReplaySubject<void> } = {};
load( load(
url: string, urlOrUrls: string | string[],
type: 'script' | 'style', type: 'script' | 'style',
content: string = '', content: string = '',
targetQuery: string = 'body', targetQuery: string = 'body',
position: InsertPosition = 'afterend', position: InsertPosition = 'afterend',
): Observable<void> { ): Observable<void> {
if (!url && !content) return; if (!urlOrUrls && !content) {
const key = url ? url.slice(url.lastIndexOf('/') + 1) : uuid(); return;
} else if (!urlOrUrls && content) {
if (this.loadedLibraries[key]) { urlOrUrls = [null];
return this.loadedLibraries[key].asObservable();
} }
this.loadedLibraries[key] = new ReplaySubject(); if (!Array.isArray(urlOrUrls)) {
urlOrUrls = [urlOrUrls];
let library;
if (type === 'script') {
library = document.createElement('script');
library.type = 'text/javascript';
if (url) {
(library as HTMLScriptElement).src = url;
}
(library as HTMLScriptElement).text = content;
} else if (url) {
library = document.createElement('link');
library.type = 'text/css';
(library as HTMLLinkElement).rel = 'stylesheet';
if (url) {
(library as HTMLLinkElement).href = url;
}
} else {
library = document.createElement('style');
(library as HTMLStyleElement).textContent = content;
} }
library.onload = () => { return new Observable(subscriber => {
this.loadedLibraries[key].next(); (urlOrUrls as string[]).forEach((url, index) => {
this.loadedLibraries[key].complete(); const key = url ? url.slice(url.lastIndexOf('/') + 1) : uuid();
};
if (this.loadedLibraries[key]) {
subscriber.next();
subscriber.complete();
return;
}
this.loadedLibraries[key] = new ReplaySubject();
let library;
if (type === 'script') {
library = document.createElement('script');
library.type = 'text/javascript';
if (url) {
(library as HTMLScriptElement).src = url;
}
(library as HTMLScriptElement).text = content;
} else if (url) {
library = document.createElement('link');
library.type = 'text/css';
(library as HTMLLinkElement).rel = 'stylesheet';
if (url) {
(library as HTMLLinkElement).href = url;
}
} else {
library = document.createElement('style');
(library as HTMLStyleElement).textContent = content;
}
library.onload = () => {
this.loadedLibraries[key].next();
this.loadedLibraries[key].complete();
document.querySelector(targetQuery).insertAdjacentElement(position, library); if (index === urlOrUrls.length - 1) {
subscriber.next();
subscriber.complete();
}
};
return this.loadedLibraries[key].asObservable(); document.querySelector(targetQuery).insertAdjacentElement(position, library);
});
});
} }
} }

35
npm/ng-packs/packages/core/src/lib/states/config.state.ts

@ -1,14 +1,14 @@
import { State, Selector, createSelector, Action, StateContext, Store } from '@ngxs/store'; import { Action, createSelector, Selector, State, StateContext, Store } from '@ngxs/store';
import { Config } from '../models/config'; import { of } from 'rxjs';
import { ABP } from '../models/common'; import { switchMap, tap } from 'rxjs/operators';
import { GetAppConfiguration, PatchRouteByName } from '../actions/config.actions';
import { ApplicationConfigurationService } from '../services/application-configuration.service';
import { tap, switchMap } from 'rxjs/operators';
import snq from 'snq'; import snq from 'snq';
import { GetAppConfiguration, PatchRouteByName } from '../actions/config.actions';
import { SetLanguage } from '../actions/session.actions'; import { SetLanguage } from '../actions/session.actions';
import { ABP } from '../models/common';
import { Config } from '../models/config';
import { ApplicationConfigurationService } from '../services/application-configuration.service';
import { organizeRoutes } from '../utils/route-utils';
import { SessionState } from './session.state'; import { SessionState } from './session.state';
import { of } from 'rxjs';
import { setChildRoute, sortRoutes, organizeRoutes } from '../utils/route-utils';
@State<Config.State>({ @State<Config.State>({
name: 'ConfigState', name: 'ConfigState',
@ -90,14 +90,31 @@ export class ConfigState {
return selector; return selector;
} }
static getSetting(key: string) { static getSetting(key: string, findContain?: boolean) {
const selector = createSelector( const selector = createSelector(
[ConfigState], [ConfigState],
(state: Config.State) => { (state: Config.State) => {
return snq(() => state.setting.values[key]); return snq(() => state.setting.values[key]);
}, },
); );
return selector;
}
static getSettings(keyword?: string) {
const selector = createSelector(
[ConfigState],
(state: Config.State) => {
if (keyword) {
const keys = snq(() => Object.keys(state.setting.values).filter(key => key.indexOf(keyword) > -1), []);
if (keys.length) {
return keys.reduce((acc, key) => ({ ...acc, [key]: state.setting.values[key] }), {});
}
}
return snq(() => state.setting.values, {});
},
);
return selector; return selector;
} }

2
npm/ng-packs/packages/theme-basic/src/lib/components/layout/layout.component.html

@ -11,7 +11,7 @@
</nav> </nav>
<div <div
[@routeAnimations]="outlet && outlet.activatedRoute && outlet.activatedRoute.routeConfig.path" [@slideFromBottom]="outlet && outlet.activatedRoute && outlet.activatedRoute.routeConfig.path"
style="padding-top: 5rem;" style="padding-top: 5rem;"
class="container" class="container"
> >

9
npm/ng-packs/packages/theme-shared/src/lib/animations/slide.animations.ts

@ -1,6 +1,7 @@
import { animate, state, style, transition, trigger, query } from '@angular/animations'; import { animate, state, style, transition, trigger, query } from '@angular/animations';
export const slideFromBottom = trigger('routeAnimations', [ export const slideFromBottom = trigger('slideFromBottom', [
state('void', style({ 'margin-top': '20px', opacity: '0' })), transition('* <=> *', [
state('*', style({ 'margin-top': '0px', opacity: '1' })), style({ 'margin-top': '20px', opacity: '0' }),
transition(':enter', [animate('0.2s ease-out', style({ opacity: '1', 'margin-top': '0px' }))]), animate('0.2s ease-out', style({ opacity: '1', 'margin-top': '0px' })),
]),
]); ]);

9
npm/ng-packs/packages/theme-shared/src/lib/components/button/button.component.ts

@ -6,14 +6,14 @@ import { Component, Input } from '@angular/core';
<button [attr.type]="type" [ngClass]="buttonClass" [disabled]="loading || disabled"> <button [attr.type]="type" [ngClass]="buttonClass" [disabled]="loading || disabled">
<i [ngClass]="icon" class="mr-1"></i><ng-content></ng-content> <i [ngClass]="icon" class="mr-1"></i><ng-content></ng-content>
</button> </button>
` `,
}) })
export class ButtonComponent { export class ButtonComponent {
@Input() @Input()
buttonClass = 'btn btn-primary'; buttonClass = 'btn btn-primary';
@Input() @Input()
type = 'button'; buttonType; // TODO: Add initial value.
@Input() @Input()
iconClass: string; iconClass: string;
@ -24,6 +24,11 @@ export class ButtonComponent {
@Input() @Input()
disabled = false; disabled = false;
/**
* @deprecated Use buttonType instead. To be deleted in v1
*/
@Input() type = 'button';
get icon(): string { get icon(): string {
return `${this.loading ? 'fa fa-pulse fa-spinner' : this.iconClass || 'd-none'}`; return `${this.loading ? 'fa fa-pulse fa-spinner' : this.iconClass || 'd-none'}`;
} }

2
npm/ng-packs/packages/theme-shared/src/lib/contants/styles.ts

@ -38,7 +38,7 @@ export default `
left: 0 !important; left: 0 !important;
width: 100% !important; width: 100% !important;
height: 100% !important; height: 100% !important;
background-color: rgba(0, 0, 0, .6) !important; background-color: rgba(0, 0, 0, 0.6) !important;
z-index: 1040 !important; z-index: 1040 !important;
} }

18
npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts

@ -32,9 +32,9 @@ export function appendScript(injector: Injector) {
'style', 'style',
styles, styles,
'head', 'head',
'afterbegin' 'afterbegin',
) /* lazyLoadService.load(null, 'script', scripts) */ ) /* lazyLoadService.load(null, 'script', scripts) */,
).pipe(take(1)); ).toPromise();
}; };
return fn; return fn;
@ -53,7 +53,7 @@ export function appendScript(injector: Injector) {
ModalComponent, ModalComponent,
ProfileComponent, ProfileComponent,
TableEmptyMessageComponent, TableEmptyMessageComponent,
ToastComponent ToastComponent,
], ],
exports: [ exports: [
BreadcrumbComponent, BreadcrumbComponent,
@ -65,9 +65,9 @@ export function appendScript(injector: Injector) {
ModalComponent, ModalComponent,
ProfileComponent, ProfileComponent,
TableEmptyMessageComponent, TableEmptyMessageComponent,
ToastComponent ToastComponent,
], ],
entryComponents: [ErrorComponent] entryComponents: [ErrorComponent],
}) })
export class ThemeSharedModule { export class ThemeSharedModule {
static forRoot(): ModuleWithProviders { static forRoot(): ModuleWithProviders {
@ -78,10 +78,10 @@ export class ThemeSharedModule {
provide: APP_INITIALIZER, provide: APP_INITIALIZER,
multi: true, multi: true,
deps: [Injector, ErrorHandler], deps: [Injector, ErrorHandler],
useFactory: appendScript useFactory: appendScript,
}, },
{ provide: MessageService, useClass: MessageService } { provide: MessageService, useClass: MessageService },
] ],
}; };
} }
} }

52
templates/app/angular/angular.json

@ -23,17 +23,31 @@
"polyfills": "src/polyfills.ts", "polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json", "tsConfig": "tsconfig.app.json",
"aot": false, "aot": false,
"assets": [ "extractCss": true,
"src/favicon.ico", "assets": ["src/favicon.ico", "src/assets"],
"src/assets"
],
"styles": [ "styles": [
"src/styles.scss", "src/styles.scss",
"node_modules/bootstrap/dist/css/bootstrap.min.css", "node_modules/bootstrap/dist/css/bootstrap.min.css",
"node_modules/font-awesome/css/font-awesome.min.css", {
"node_modules/primeng/resources/themes/nova-light/theme.css", "input": "node_modules/font-awesome/css/font-awesome.min.css",
"node_modules/primeicons/primeicons.css", "lazy": true,
"node_modules/primeng/resources/primeng.min.css" "bundleName": "font-awesome.min"
},
{
"input": "node_modules/primeng/resources/themes/nova-light/theme.css",
"lazy": true,
"bundleName": "primeng-nova-light-theme"
},
{
"input": "node_modules/primeicons/primeicons.css",
"lazy": true,
"bundleName": "primeicons"
},
{
"input": "node_modules/primeng/resources/primeng.min.css",
"lazy": true,
"bundleName": "primeng.min"
}
], ],
"scripts": [] "scripts": []
}, },
@ -100,10 +114,7 @@
"polyfills": "src/polyfills.ts", "polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json", "tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js", "karmaConfig": "karma.conf.js",
"assets": [ "assets": ["src/favicon.ico", "src/assets"],
"src/favicon.ico",
"src/assets"
],
"styles": [ "styles": [
"src/styles.scss", "src/styles.scss",
"node_modules/bootstrap/dist/css/bootstrap.min.css", "node_modules/bootstrap/dist/css/bootstrap.min.css",
@ -118,14 +129,8 @@
"lint": { "lint": {
"builder": "@angular-devkit/build-angular:tslint", "builder": "@angular-devkit/build-angular:tslint",
"options": { "options": {
"tsConfig": [ "tsConfig": ["tsconfig.app.json", "tsconfig.spec.json", "e2e/tsconfig.json"],
"tsconfig.app.json", "exclude": ["**/node_modules/**"]
"tsconfig.spec.json",
"e2e/tsconfig.json"
],
"exclude": [
"**/node_modules/**"
]
} }
}, },
"e2e": { "e2e": {
@ -143,8 +148,5 @@
} }
} }
}, },
"defaultProject": "myProjectName", "defaultProject": "myProjectName"
"cli": { }
"analytics": "07ef29be-2b85-4919-9f78-44994f63b8b7"
}
}

18
templates/app/angular/src/app/app.component.ts

@ -1,4 +1,5 @@
import { Component } from '@angular/core'; import { LazyLoadService } from '@abp/ng.core';
import { Component, OnInit } from '@angular/core';
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
@ -7,4 +8,17 @@ import { Component } from '@angular/core';
<router-outlet></router-outlet> <router-outlet></router-outlet>
`, `,
}) })
export class AppComponent {} export class AppComponent implements OnInit {
constructor(private lazyLoadService: LazyLoadService) {}
ngOnInit() {
this.lazyLoadService
.load(
['primeng.min.css', 'primeicons.css', 'primeng-nova-light-theme.css', 'font-awesome.min.css'],
'style',
null,
'head',
)
.subscribe();
}
}

Loading…
Cancel
Save