Last active
June 13, 2021 21:51
-
-
Save jhades/c96635b2b48135516e7ba04534758608 to your computer and use it in GitHub Desktop.
Angular Universal Guide
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"server": { | |
"builder": "@angular-devkit/build-angular:server", | |
"options": { | |
"outputPath": "dist-server", | |
"main": "src/main.server.ts", | |
"tsConfig": "src/tsconfig.server.json" | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { enableProdMode } from '@angular/core'; | |
import { environment } from './environments/environment'; | |
if (environment.production) { | |
enableProdMode(); | |
} | |
export { AppServerModule } from './app/app.server.module'; | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { NgModule } from '@angular/core'; | |
import { ServerModule } from '@angular/platform-server'; | |
import { AppModule } from './app.module'; | |
import { AppComponent } from './app.component'; | |
@NgModule({ | |
imports: [ | |
AppModule, | |
ServerModule, | |
], | |
bootstrap: [AppComponent], | |
}) | |
export class AppServerModule {} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@NgModule({ | |
declarations: [ | |
AppComponent, | |
... | |
], | |
imports: [ | |
BrowserModule.withServerTransition({ appId: 'serverApp' }), | |
... | |
], | |
providers: [ | |
... | |
], | |
bootstrap: [AppComponent], | |
}) | |
export class AppModule { | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'zone.js/dist/zone-node'; | |
import 'reflect-metadata'; | |
import {renderModuleFactory} from '@angular/platform-server'; | |
import {writeFileSync} from 'fs'; | |
const {AppServerModuleNgFactory} = require('./dist-server/bundle'); | |
renderModuleFactory(AppServerModuleNgFactory, { | |
document: '<app-root></app-root>', | |
url: '/' | |
}) | |
.then(html => { | |
console.log('Pre-rendering successful, saving prerender.html'); | |
writeFileSync('./prerender.html', html); | |
}) | |
.catch(error => { | |
console.error('Error occurred:', error); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const {AppServerModuleNgFactory} = require('./dist-server/bundle'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
... | |
renderModuleFactory(AppServerModuleNgFactory, { | |
document: '<app-root></app-root>', | |
url: '/' | |
}) | |
... | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'zone.js/dist/zone-node'; | |
import 'reflect-metadata'; | |
import {renderModuleFactory} from '@angular/platform-server'; | |
import * as express from 'express'; | |
import { readFileSync } from 'fs'; | |
import { enableProdMode } from '@angular/core'; | |
const {AppServerModuleNgFactory} = require('./dist-server/bundle'); | |
enableProdMode(); | |
const app = express(); | |
const indexHtml = readFileSync(__dirname + '/dist/index.html', 'utf-8').toString(); | |
app.get('*.*', express.static(__dirname + '/dist', { | |
maxAge: '1y' | |
})); | |
app.route('*').get((req, res) => { | |
renderModuleFactory(AppServerModuleNgFactory, { | |
document: indexHtml, | |
url: req.url | |
}) | |
.then(html => { | |
res.status(200).send(html); | |
}) | |
.catch(err => { | |
console.log(err); | |
res.sendStatus(500); | |
}); | |
}); | |
app.listen(9000, () => { | |
console.log(`Angular Universal Node Express server listening on http://localhost:9000`); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<title>Angular Universal Course</title> | |
<base href="/"> | |
<meta name="viewport" content="width=device-width,initial-scale=1"> | |
<link rel="icon" type="image/x-icon" href="favicon.ico"> | |
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> | |
<link href="https://fonts.googleapis.com/css?family=Roboto|Roboto+Mono:300" rel="stylesheet"> | |
<link href="styles.faa5dcd931f22d491e1f.bundle.css" rel="stylesheet"/> | |
</head> | |
<body> | |
<app-root></app-root> | |
<script type="text/javascript" src="inline.6a5615aec11679fd2f49.bundle.js"></script> | |
<script type="text/javascript" src="polyfills.9afba58cc5c5e906563e.bundle.js"></script> | |
<script type="text/javascript" src="main.f9c77e3090fdfb4a85b6.bundle.js"></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
... | |
const {AppServerModuleNgFactory} = require('./dist-server/bundle'); | |
enableProdMode(); | |
const app = express(); | |
const indexHtml = readFileSync(__dirname + '/dist/index.html', 'utf-8').toString(); | |
... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
app.route('*').get((req, res) => { | |
renderModuleFactory(AppServerModuleNgFactory, { | |
document: indexHtml, | |
url: req.url | |
}) | |
.then(html => { | |
res.status(200).send(html); | |
}) | |
.catch(err => { | |
console.log(err); | |
res.sendStatus(500); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<title>Learn Angular</title> | |
<base href="/"> | |
<meta name="viewport" content="width=device-width,initial-scale=1"> | |
<link rel="icon" type="image/x-icon" href="favicon.ico"> | |
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> | |
<link href="https://fonts.googleapis.com/css?family=Roboto|Roboto+Mono:300" rel="stylesheet"> | |
<link href="styles.faa5dcd931f22d491e1f.bundle.css" rel="stylesheet"/> | |
.... we will find here a LOT of inline style tags, for styling Angular components .... | |
</head> | |
<body> | |
<app-root> | |
.... This is no longer empty, there is a LOT of HTML here .... | |
</app-root> | |
<script type="text/javascript" src="inline.6a5615aec11679fd2f49.bundle.js"></script> | |
<script type="text/javascript" src="polyfills.9afba58cc5c5e906563e.bundle.js"></script> | |
<script type="text/javascript" src="main.f9c77e3090fdfb4a85b6.bundle.js"></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script type="text/javascript" src="main.f9c77e3090fdfb4a85b6.bundle.js"></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
app.get('*.*', express.static(__dirname + '/dist', { | |
maxAge: '1y' | |
})); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
app.listen(9000, () => { | |
console.log(`Angular Universal Node Express server listening on http://localhost:9000`); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'zone.js/dist/zone-node'; | |
import 'reflect-metadata'; | |
import {renderModuleFactory} from '@angular/platform-server'; | |
import * as express from 'express'; | |
import { readFileSync } from 'fs'; | |
import { enableProdMode } from '@angular/core'; | |
import { ngExpressEngine } from '@nguniversal/express-engine'; | |
import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader'; | |
const {AppServerModuleNgFactory, LAZY_MODULE_MAP} = require('./dist-server/bundle'); | |
enableProdMode(); | |
const app = express(); | |
const distFolder = __dirname + '/dist'; | |
app.engine('html', ngExpressEngine({ | |
bootstrap: AppServerModuleNgFactory, | |
providers: [provideModuleMap(LAZY_MODULE_MAP)] | |
})); | |
app.set('view engine', 'html'); | |
app.set('views', distFolder); | |
app.get('*.*', express.static(distFolder, { | |
maxAge: '1y' | |
})); | |
app.get('*', (req, res) => { | |
res.render('index', {req}); | |
}); | |
app.listen(9000, () => { | |
console.log(`Angular Universal Node Express server listening on http://localhost:9000`); | |
}); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Component({ | |
selector: 'course', | |
templateUrl: './course.component.html', | |
styleUrls: ['./course.component.css'] | |
}) | |
export class CourseComponent implements OnInit { | |
course: Course; | |
constructor(private title: Title, | |
private meta: Meta) {} | |
ngOnInit() { | |
this.course = this.route.snapshot.data['course']; | |
.... | |
// SEO metadata | |
this.title.setTitle(this.course.description); | |
this.meta.addTag({name: 'description', content: this.course.longDescription}); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
ngOnInit() { | |
this.course = this.route.snapshot.data['course']; | |
.... | |
// SEO metadata | |
this.title.setTitle(this.course.description); | |
this.meta.addTag({name: 'description', content: this.course.longDescription}); | |
// Twitter metadata | |
this.meta.addTag({name: 'twitter:card', content: 'summary'}); | |
this.meta.addTag({name: 'twitter:site', content: '@AngularUniv'}); | |
this.meta.addTag({name: 'twitter:title', content: this.course.description}); | |
this.meta.addTag({name: 'twitter:description', content: this.course.description}); | |
this.meta.addTag({name: 'twitter:text:description', content: this.course.description}); | |
this.meta.addTag({name: 'twitter:image', content: 'https://avatars3.githubusercontent.com/u/16628445?v=3&s=200'}); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<mat-sidenav-container fullscreen> | |
... | |
<router-outlet></router-outlet> | |
<div class="spinner-container" *appShellRender> | |
<mat-spinner></mat-spinner> | |
</div> | |
</mat-sidenav-container> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="course"> | |
<h2>{{course?.description}}</h2> | |
<img class="course-thumbnail" [src]="course?.iconUrl"> | |
<mat-table [dataSource]="dataSource" *appShellNoRender> | |
.... | |
</mat-table> | |
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Directive({ | |
selector: '[appShellRender]' | |
}) | |
export class AppShellRenderDirective implements OnInit { | |
constructor( | |
private viewContainer: ViewContainerRef, | |
private templateRef: TemplateRef<any>, | |
@Inject(PLATFORM_ID) private platformId) {} | |
ngOnInit() { | |
if (isPlatformServer(this.platformId)) { | |
this.viewContainer.createEmbeddedView(this.templateRef); | |
} | |
else { | |
this.viewContainer.clear(); | |
} | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="spinner-container"> | |
<mat-spinner></mat-spinner> | |
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
ngOnInit() { | |
if (isPlatformServer(this.platformId)) { | |
this.viewContainer.createEmbeddedView(this.templateRef); | |
} | |
else { | |
this.viewContainer.clear(); | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Directive({ | |
selector: '[appShellNoRender]' | |
}) | |
export class AppShellNoRenderDirective implements OnInit { | |
constructor( | |
private viewContainer: ViewContainerRef, | |
private templateRef: TemplateRef<any>, | |
@Inject(PLATFORM_ID) private platformId) {} | |
ngOnInit() { | |
if (isPlatformServer(this.platformId)) { | |
this.viewContainer.clear(); | |
} | |
else { | |
this.viewContainer.createEmbeddedView(this.templateRef); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Injectable() | |
export class CourseResolver implements Resolve<Course> { | |
constructor(private coursesService: CoursesService) {} | |
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Course> { | |
const courseId = route.params['id']; | |
return this.coursesService.findCourseById(courseId); | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {PLATFORM_ID} from '@angular/core'; | |
import {isPlatformServer} from '@angular/common'; | |
import {makeStateKey, TransferState} from '@angular/platform-browser'; | |
@Injectable() | |
export class CourseResolver implements Resolve<Course> { | |
constructor( | |
private coursesService: CoursesService, | |
@Inject(PLATFORM_ID) private platformId, | |
private transferState:TransferState) {} | |
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Course> { | |
const courseId = route.params['id']; | |
const COURSE_KEY = makeStateKey<Course>('course-' + courseId); | |
if (this.transferState.hasKey(COURSE_KEY)) { | |
const course = this.transferState.get<Course>(COURSE_KEY, null); | |
this.transferState.remove(COURSE_KEY); | |
return of(course); | |
} | |
else { | |
return this.coursesService.findCourseById(courseId) | |
.pipe( | |
tap(course => { | |
if (isPlatformServer(this.platformId)) { | |
this.transferState.set(COURSE_KEY, course); | |
} | |
}) | |
); | |
} | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const COURSE_KEY = makeStateKey<Course>('course-' + courseId); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
if (this.transferState.hasKey(COURSE_KEY)) { | |
.... | |
} | |
else { | |
.... | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
... | |
return this.coursesService.findCourseById(courseId) | |
.pipe( | |
tap(course => { | |
if (isPlatformServer(this.platformId)) { | |
this.transferState.set(COURSE_KEY, course); | |
} | |
}) | |
); | |
... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
... | |
if (this.transferState.hasKey(COURSE_KEY)) { | |
const course = this.transferState.get<Course>(COURSE_KEY, null); | |
this.transferState.remove(COURSE_KEY); | |
return of(course); | |
} | |
... | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Reading/using your Angular Universal guide. It's fantastic. Thanks!
Just want to mention that the file
05.ts
is missing});
at the end.