Skip to content

Commit ef4d7a9

Browse files
committed
Sometimes we need to hide content bouncing effect via fullscreen loader on first app loading #22
1 parent dc9d538 commit ef4d7a9

16 files changed

+289
-15
lines changed

project/application/package-lock.json

+9-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

project/application/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"domino": "^2.1.0",
3838
"es5-shim": "^4.5.10",
3939
"es6-shim": "^0.35.3",
40+
"isbot": "^2.2.0",
4041
"rxjs": "^6.0.0",
4142
"ts-loader": "^4.4.2",
4243
"zone.js": "~0.8.26"

project/application/server.ts

+8
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const DIST_FOLDER = join(process.cwd(), 'dist');
1919

2020
// * NOTE :: leave this as require() since this file is built Dynamically from webpack
2121
const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./tmp/server/main');
22+
const isBot = require('isbot');
2223

2324
// Import module map for lazy loading
2425
import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';
@@ -64,6 +65,13 @@ app.get('*.*', express.static(join(DIST_FOLDER, 'browser')));
6465
// All regular routes use the Universal engine
6566
app.get('*', (req, res) => {
6667
global['navigator'] = req['headers']['user-agent'];
68+
const userAgent = req['headers']['user-agent'];
69+
70+
req['headers']['crawler'] = false;
71+
if (isBot(userAgent) === true) {
72+
req['headers']['crawler'] = true;
73+
}
74+
6775
res.render(join(DIST_FOLDER, 'browser', 'index.html'), { req });
6876
});
6977

Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
1+
<!--Full screen loader-->
2+
<div class="loading" *ngIf="serverAnimationService.active === true">Loading&#8230;</div>
3+
<!--/.Full screen loade-->
4+
15
<router-outlet></router-outlet>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
.loading { /* Absolute Center Spinner */
2+
position: fixed;
3+
z-index: 999;
4+
height: 2em;
5+
width: 2em;
6+
overflow: show;
7+
margin: auto;
8+
top: 0;
9+
left: 0;
10+
bottom: 0;
11+
right: 0;
12+
&:before { /* Transparent Overlay */
13+
content: "";
14+
display: block;
15+
position: fixed;
16+
top: 0;
17+
left: 0;
18+
width: 100%;
19+
height: 100%;
20+
background: rgba(255, 255, 255, 1);
21+
}
22+
&:not(:required) { /* :not(:required) hides these rules from IE9 and below */
23+
/* hide "loading..." text */
24+
font: 0/0 a;
25+
color: transparent;
26+
text-shadow: none;
27+
background-color: transparent;
28+
border: 0;
29+
&:after {
30+
content: "";
31+
display: block;
32+
font-size: 10px;
33+
width: 1em;
34+
height: 1em;
35+
margin-top: -0.5em;
36+
-webkit-animation: spinner 1500ms infinite linear;
37+
-moz-animation: spinner 1500ms infinite linear;
38+
-ms-animation: spinner 1500ms infinite linear;
39+
-o-animation: spinner 1500ms infinite linear;
40+
animation: spinner 1500ms infinite linear;
41+
border-radius: 0.5em;
42+
-webkit-box-shadow: rgba(0, 0, 0, 0.75) 1.5em 0 0 0, rgba(0, 0, 0, 0.75) 1.1em 1.1em 0 0,
43+
rgba(0, 0, 0, 0.75) 0 1.5em 0 0, rgba(0, 0, 0, 0.75) -1.1em 1.1em 0 0, rgba(0, 0, 0, 0.75) -1.5em 0 0 0,
44+
rgba(0, 0, 0, 0.75) -1.1em -1.1em 0 0, rgba(0, 0, 0, 0.75) 0 -1.5em 0 0,
45+
rgba(0, 0, 0, 0.75) 1.1em -1.1em 0 0;
46+
box-shadow: rgba(0, 0, 0, 0.75) 1.5em 0 0 0, rgba(0, 0, 0, 0.75) 1.1em 1.1em 0 0,
47+
rgba(0, 0, 0, 0.75) 0 1.5em 0 0, rgba(0, 0, 0, 0.75) -1.1em 1.1em 0 0, rgba(0, 0, 0, 0.75) -1.5em 0 0 0,
48+
rgba(0, 0, 0, 0.75) -1.1em -1.1em 0 0, rgba(0, 0, 0, 0.75) 0 -1.5em 0 0,
49+
rgba(0, 0, 0, 0.75) 1.1em -1.1em 0 0;
50+
}
51+
}
52+
}
53+
54+
/* Animation */
55+
@-webkit-keyframes spinner {
56+
0% {
57+
-webkit-transform: rotate(0deg);
58+
-moz-transform: rotate(0deg);
59+
-ms-transform: rotate(0deg);
60+
-o-transform: rotate(0deg);
61+
transform: rotate(0deg);
62+
}
63+
64+
100% {
65+
-webkit-transform: rotate(360deg);
66+
-moz-transform: rotate(360deg);
67+
-ms-transform: rotate(360deg);
68+
-o-transform: rotate(360deg);
69+
transform: rotate(360deg);
70+
}
71+
}
72+
73+
@-moz-keyframes spinner {
74+
0% {
75+
-webkit-transform: rotate(0deg);
76+
-moz-transform: rotate(0deg);
77+
-ms-transform: rotate(0deg);
78+
-o-transform: rotate(0deg);
79+
transform: rotate(0deg);
80+
}
81+
82+
100% {
83+
-webkit-transform: rotate(360deg);
84+
-moz-transform: rotate(360deg);
85+
-ms-transform: rotate(360deg);
86+
-o-transform: rotate(360deg);
87+
transform: rotate(360deg);
88+
}
89+
}
90+
91+
@-o-keyframes spinner {
92+
0% {
93+
-webkit-transform: rotate(0deg);
94+
-moz-transform: rotate(0deg);
95+
-ms-transform: rotate(0deg);
96+
-o-transform: rotate(0deg);
97+
transform: rotate(0deg);
98+
}
99+
100+
100% {
101+
-webkit-transform: rotate(360deg);
102+
-moz-transform: rotate(360deg);
103+
-ms-transform: rotate(360deg);
104+
-o-transform: rotate(360deg);
105+
transform: rotate(360deg);
106+
}
107+
}
108+
109+
@keyframes spinner {
110+
0% {
111+
-webkit-transform: rotate(0deg);
112+
-moz-transform: rotate(0deg);
113+
-ms-transform: rotate(0deg);
114+
-o-transform: rotate(0deg);
115+
transform: rotate(0deg);
116+
}
117+
118+
100% {
119+
-webkit-transform: rotate(360deg);
120+
-moz-transform: rotate(360deg);
121+
-ms-transform: rotate(360deg);
122+
-o-transform: rotate(360deg);
123+
transform: rotate(360deg);
124+
}
125+
}

project/application/src/app/app.component.spec.ts

+8-3
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,34 @@
1-
import { TestBed, async } from '@angular/core/testing';
1+
import { TestBed, async, ComponentFixture } from '@angular/core/testing';
22
import { RouterTestingModule } from '@angular/router/testing';
3+
import { TransferState } from '@angular/platform-browser';
34

45
import { AppComponent } from './app.component';
6+
import { ServerAnimationService } from './modules/core/services/server-animation/server-animation.service';
7+
import { BotCrawlerService } from './modules/core/services/bot-crawler/bot-crawler.service';
8+
import { TransferStateService } from './modules/core/services/transfer-state/transfer-state.service';
59

610
describe('AppComponent', () => {
11+
let fixture: ComponentFixture<AppComponent>;
712
beforeEach(
813
async(() => {
914
TestBed.configureTestingModule({
1015
imports: [RouterTestingModule],
1116
declarations: [AppComponent],
17+
providers: [ServerAnimationService, BotCrawlerService, TransferState, TransferStateService],
1218
}).compileComponents();
19+
fixture = TestBed.createComponent(AppComponent);
1320
})
1421
);
1522
it(
1623
'should create the app',
1724
async(() => {
18-
const fixture = TestBed.createComponent(AppComponent);
1925
const app = fixture.debugElement.componentInstance;
2026
expect(app).toBeTruthy();
2127
})
2228
);
2329
it(
2430
`should have as title 'Welcome to angular ssr app!'`,
2531
async(() => {
26-
const fixture = TestBed.createComponent(AppComponent);
2732
const app = fixture.debugElement.componentInstance;
2833
expect(app.title).toEqual('Welcome to angular ssr app!');
2934
})
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
import { Component } from '@angular/core';
22

3+
import { ServerAnimationService } from './modules/core/services/server-animation/server-animation.service';
4+
35
@Component({
46
selector: 'app-root',
57
templateUrl: './app.component.html',
68
styleUrls: ['./app.component.scss'],
79
})
810
export class AppComponent {
911
title = 'Welcome to angular ssr app!';
12+
13+
constructor(public serverAnimationService: ServerAnimationService) {}
1014
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { TestBed, inject } from '@angular/core/testing';
2+
import { TransferState } from '@angular/platform-browser';
3+
4+
import { BotCrawlerService } from './bot-crawler.service';
5+
import { TransferStateService } from '../transfer-state/transfer-state.service';
6+
7+
describe('BotCrawlerService', () => {
8+
beforeEach(() => {
9+
TestBed.configureTestingModule({
10+
providers: [BotCrawlerService, TransferState, TransferStateService],
11+
});
12+
});
13+
14+
it(
15+
'should be created',
16+
inject([BotCrawlerService], (service: BotCrawlerService) => {
17+
expect(service).toBeTruthy();
18+
})
19+
);
20+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { Injectable, Injector, Inject, PLATFORM_ID } from '@angular/core';
2+
import { isPlatformServer, isPlatformBrowser } from '@angular/common';
3+
import { REQUEST } from '@nguniversal/express-engine/tokens';
4+
5+
import { CoreModule } from '../../core.module';
6+
import { TransferStateService } from '../transfer-state/transfer-state.service';
7+
8+
interface PayloadDefinition {
9+
payload: {
10+
crawler: boolean;
11+
};
12+
}
13+
14+
@Injectable({
15+
providedIn: CoreModule,
16+
})
17+
export class BotCrawlerService {
18+
private payloadServerName = 'BotCrawlerServicePayload';
19+
private payload = () =>
20+
new Promise((resolve, reject) => {
21+
let crawler;
22+
if (isPlatformServer(this.platformId)) {
23+
const req = this.injector.get(REQUEST);
24+
crawler = req.headers.crawler;
25+
} else if (isPlatformBrowser(this.platformId)) {
26+
crawler = false;
27+
} else {
28+
reject();
29+
}
30+
31+
const payload = { crawler };
32+
33+
resolve({ payload });
34+
});
35+
36+
constructor(
37+
private injector: Injector,
38+
@Inject(PLATFORM_ID) private platformId: Object,
39+
private transferStateService: TransferStateService
40+
) {}
41+
42+
public checkIsCrawler(): Promise<boolean | any> {
43+
return new Promise((resolve, reject) => {
44+
this.transferStateService.savePayload(this.payload, this.payloadServerName).then(
45+
(res: PayloadDefinition) => {
46+
resolve(res.payload ? res.payload.crawler : false);
47+
},
48+
error => {
49+
reject(error);
50+
}
51+
);
52+
});
53+
}
54+
}

project/application/src/app/modules/core/services/document-link/document-link.service.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export class DocumentLinkService {
4747
this.payloadServerName
4848
)
4949
.then(
50-
(payload: PayloadDefinition) => {
50+
(res: PayloadDefinition) => {
5151
// payload received
5252
},
5353
error => {
@@ -69,7 +69,7 @@ export class DocumentLinkService {
6969
this.payloadServerName
7070
)
7171
.then(
72-
(payload: PayloadDefinition) => {
72+
(res: PayloadDefinition) => {
7373
// payload received
7474
},
7575
error => {

project/application/src/app/modules/core/services/document-meta/document-meta.service.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export class DocumentMetaService {
3333
this.payloadServerName
3434
)
3535
.then(
36-
(payload: PayloadDefinition) => {
36+
(res: PayloadDefinition) => {
3737
// payload received
3838
},
3939
error => {
@@ -55,7 +55,7 @@ export class DocumentMetaService {
5555
this.payloadServerName
5656
)
5757
.then(
58-
(payload: PayloadDefinition) => {
58+
(res: PayloadDefinition) => {
5959
// payload received
6060
},
6161
error => {

project/application/src/app/modules/core/services/document-title/document-title.service.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export class DocumentTitleService {
3131
this.payloadServerName
3232
)
3333
.then(
34-
(payload: PayloadDefinition) => {
34+
(res: PayloadDefinition) => {
3535
// payload received
3636
},
3737
error => {

0 commit comments

Comments
 (0)