Browse Source

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

Feature/bundle size
pull/1873/head
Yasin Aydın 6 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
/tmp
/out-tsc
/dist/dev-app
# Only exists if Bazel was run
/bazel-out

25
npm/ng-packs/angular.json

@ -434,13 +434,30 @@
"tsConfig": "apps/dev-app/tsconfig.app.json",
"aot": false,
"assets": ["apps/dev-app/src/favicon.ico", "apps/dev-app/src/assets"],
"extractCss": true,
"styles": [
"apps/dev-app/src/styles.scss",
"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",
"node_modules/primeicons/primeicons.css",
"node_modules/primeng/resources/primeng.min.css"
{
"input": "node_modules/font-awesome/css/font-awesome.min.css",
"lazy": true,
"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": []
},

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({
selector: 'app-root',
@ -7,4 +8,17 @@ import { Component } from '@angular/core';
<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 interface Response {
localization: Localization;
auth: Auth;
setting: Setting;
setting: Value;
currentUser: CurrentUser;
features: Features;
features: Value;
}
export interface Localization {
@ -32,8 +34,8 @@ export namespace ApplicationConfiguration {
[key: string]: boolean;
}
export interface Setting {
values: { [key: string]: 'Abp.Localization.DefaultLanguage' };
export interface Value {
values: ABP.Dictionary<string>;
}
export interface CurrentUser {
@ -42,8 +44,4 @@ export namespace ApplicationConfiguration {
tenantId: 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> } = {};
load(
url: string,
urlOrUrls: string | string[],
type: 'script' | 'style',
content: string = '',
targetQuery: string = 'body',
position: InsertPosition = 'afterend',
): Observable<void> {
if (!url && !content) return;
const key = url ? url.slice(url.lastIndexOf('/') + 1) : uuid();
if (this.loadedLibraries[key]) {
return this.loadedLibraries[key].asObservable();
if (!urlOrUrls && !content) {
return;
} else if (!urlOrUrls && content) {
urlOrUrls = [null];
}
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;
if (!Array.isArray(urlOrUrls)) {
urlOrUrls = [urlOrUrls];
}
library.onload = () => {
this.loadedLibraries[key].next();
this.loadedLibraries[key].complete();
};
return new Observable(subscriber => {
(urlOrUrls as string[]).forEach((url, index) => {
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 { Config } from '../models/config';
import { ABP } from '../models/common';
import { GetAppConfiguration, PatchRouteByName } from '../actions/config.actions';
import { ApplicationConfigurationService } from '../services/application-configuration.service';
import { tap, switchMap } from 'rxjs/operators';
import { Action, createSelector, Selector, State, StateContext, Store } from '@ngxs/store';
import { of } from 'rxjs';
import { switchMap, tap } from 'rxjs/operators';
import snq from 'snq';
import { GetAppConfiguration, PatchRouteByName } from '../actions/config.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 { of } from 'rxjs';
import { setChildRoute, sortRoutes, organizeRoutes } from '../utils/route-utils';
@State<Config.State>({
name: 'ConfigState',
@ -90,14 +90,31 @@ export class ConfigState {
return selector;
}
static getSetting(key: string) {
static getSetting(key: string, findContain?: boolean) {
const selector = createSelector(
[ConfigState],
(state: Config.State) => {
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;
}

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

@ -11,7 +11,7 @@
</nav>
<div
[@routeAnimations]="outlet && outlet.activatedRoute && outlet.activatedRoute.routeConfig.path"
[@slideFromBottom]="outlet && outlet.activatedRoute && outlet.activatedRoute.routeConfig.path"
style="padding-top: 5rem;"
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';
export const slideFromBottom = trigger('routeAnimations', [
state('void', style({ 'margin-top': '20px', opacity: '0' })),
state('*', style({ 'margin-top': '0px', opacity: '1' })),
transition(':enter', [animate('0.2s ease-out', style({ opacity: '1', 'margin-top': '0px' }))]),
export const slideFromBottom = trigger('slideFromBottom', [
transition('* <=> *', [
style({ 'margin-top': '20px', opacity: '0' }),
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">
<i [ngClass]="icon" class="mr-1"></i><ng-content></ng-content>
</button>
`
`,
})
export class ButtonComponent {
@Input()
buttonClass = 'btn btn-primary';
@Input()
type = 'button';
buttonType; // TODO: Add initial value.
@Input()
iconClass: string;
@ -24,6 +24,11 @@ export class ButtonComponent {
@Input()
disabled = false;
/**
* @deprecated Use buttonType instead. To be deleted in v1
*/
@Input() type = 'button';
get icon(): string {
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;
width: 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;
}

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

@ -32,9 +32,9 @@ export function appendScript(injector: Injector) {
'style',
styles,
'head',
'afterbegin'
) /* lazyLoadService.load(null, 'script', scripts) */
).pipe(take(1));
'afterbegin',
) /* lazyLoadService.load(null, 'script', scripts) */,
).toPromise();
};
return fn;
@ -53,7 +53,7 @@ export function appendScript(injector: Injector) {
ModalComponent,
ProfileComponent,
TableEmptyMessageComponent,
ToastComponent
ToastComponent,
],
exports: [
BreadcrumbComponent,
@ -65,9 +65,9 @@ export function appendScript(injector: Injector) {
ModalComponent,
ProfileComponent,
TableEmptyMessageComponent,
ToastComponent
ToastComponent,
],
entryComponents: [ErrorComponent]
entryComponents: [ErrorComponent],
})
export class ThemeSharedModule {
static forRoot(): ModuleWithProviders {
@ -78,10 +78,10 @@ export class ThemeSharedModule {
provide: APP_INITIALIZER,
multi: true,
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",
"tsConfig": "tsconfig.app.json",
"aot": false,
"assets": [
"src/favicon.ico",
"src/assets"
],
"extractCss": true,
"assets": ["src/favicon.ico", "src/assets"],
"styles": [
"src/styles.scss",
"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",
"node_modules/primeicons/primeicons.css",
"node_modules/primeng/resources/primeng.min.css"
{
"input": "node_modules/font-awesome/css/font-awesome.min.css",
"lazy": true,
"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": []
},
@ -100,10 +114,7 @@
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"assets": [
"src/favicon.ico",
"src/assets"
],
"assets": ["src/favicon.ico", "src/assets"],
"styles": [
"src/styles.scss",
"node_modules/bootstrap/dist/css/bootstrap.min.css",
@ -118,14 +129,8 @@
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"tsconfig.app.json",
"tsconfig.spec.json",
"e2e/tsconfig.json"
],
"exclude": [
"**/node_modules/**"
]
"tsConfig": ["tsconfig.app.json", "tsconfig.spec.json", "e2e/tsconfig.json"],
"exclude": ["**/node_modules/**"]
}
},
"e2e": {
@ -143,8 +148,5 @@
}
}
},
"defaultProject": "myProjectName",
"cli": {
"analytics": "07ef29be-2b85-4919-9f78-44994f63b8b7"
}
}
"defaultProject": "myProjectName"
}

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({
selector: 'app-root',
@ -7,4 +8,17 @@ import { Component } from '@angular/core';
<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