├── .gitignore
├── .prettierrc
├── LICENSE
├── README.md
├── angular.json
├── browserslist
├── karma.conf.js
├── package-lock.json
├── package.json
├── server.ts
├── server
├── app.controller.ts
├── app.module.ts
└── main.ts
├── src
├── app
│ ├── app.component.ts
│ ├── app.module.ts
│ ├── app.server.module.ts
│ ├── components
│ │ └── home
│ │ │ └── home.component.ts
│ ├── interfaces
│ │ └── speakers.interface.ts
│ └── modules
│ │ ├── shared
│ │ ├── interceptors
│ │ │ └── universal-interceptor.service.ts
│ │ └── shared.module.ts
│ │ └── speakers
│ │ ├── speakers-list
│ │ ├── speakers-list.component.ts
│ │ └── speakers.service.ts
│ │ └── speakers.module.ts
├── assets
│ └── .gitkeep
├── environments
│ ├── environment.prod.ts
│ └── environment.ts
├── favicon.ico
├── index.html
├── main.server.ts
├── main.ts
├── polyfills.ts
└── styles.css
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.server.json
└── tslint.json
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | .DS_Store
3 | .vscode
4 |
5 | # Built #
6 | /__build__/
7 | /__server_build__/
8 | /node_modules/
9 | /typings/
10 | /tsd_typings/
11 | /dist/
12 | /dist-server/
13 | /compiled/
14 |
15 | # Node #
16 | *.log
17 | /npm-debug.log.*
18 |
19 | # Webpack #
20 | webpack.records.json
21 |
22 | # Angular #
23 | *.ngfactory.ts
24 | *.css.shim.ts
25 | *.ngsummary.json
26 | *.metadata.json
27 | *.shim.ngstyle.ts
28 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true
3 | }
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | (The MIT License)
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | 'Software'), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Nest & Angular Universal Starter
2 |
3 | A minimal [**Nest**](https://github.com/nestjs/nest) and Angular starter for Universal using the
4 | [Angular CLI](https://github.com/angular/angular-cli). If you're looking for the Angular Universal repo go to
5 | [angular/universal](https://github.com/angular/universal).
6 |
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | Made with :heart: by Trilon.io
17 |
18 | ---
19 |
20 | ## Getting Started
21 |
22 | This demo is built following the [Angular-CLI Wiki guide](https://github.com/angular/angular-cli/wiki/stories-universal-rendering).
23 |
24 | ### Installation
25 |
26 | - `npm i`
27 |
28 | ### Development (Client-side only rendering)
29 |
30 | - `npm start` which will run `ng serve`.
31 |
32 | ### Development (Server-side rendering)
33 |
34 | - `npm run dev:ssr`.
35 |
36 | ### Production
37 |
38 | \*`npm run build:ssr && npm run serve:ssr`
39 |
40 | - Compiles your application and spins up a Nest server to serve your Universal application on `http://localhost:4000`.
41 |
42 | \*`npm run prerender`
43 |
44 | - Compiles your application and prerenders your applications files
45 |
46 | # License
47 |
48 | [](/LICENSE)
49 |
--------------------------------------------------------------------------------
/angular.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3 | "version": 1,
4 | "newProjectRoot": "projects",
5 | "projects": {
6 | "universal-starter-v9": {
7 | "projectType": "application",
8 | "schematics": {
9 | "@schematics/angular:component": {
10 | "style": "scss"
11 | }
12 | },
13 | "root": "",
14 | "sourceRoot": "src",
15 | "prefix": "app",
16 | "architect": {
17 | "build": {
18 | "builder": "@angular-devkit/build-angular:browser",
19 | "options": {
20 | "outputPath": "dist/universal-starter-v9/browser",
21 | "index": "src/index.html",
22 | "main": "src/main.ts",
23 | "polyfills": "src/polyfills.ts",
24 | "tsConfig": "tsconfig.app.json",
25 | "aot": true,
26 | "assets": ["src/favicon.ico", "src/assets"],
27 | "styles": ["src/styles.css"],
28 | "scripts": []
29 | },
30 | "configurations": {
31 | "production": {
32 | "fileReplacements": [
33 | {
34 | "replace": "src/environments/environment.ts",
35 | "with": "src/environments/environment.prod.ts"
36 | }
37 | ],
38 | "optimization": true,
39 | "outputHashing": "all",
40 | "sourceMap": false,
41 | "extractCss": true,
42 | "namedChunks": false,
43 | "extractLicenses": true,
44 | "vendorChunk": false,
45 | "buildOptimizer": true,
46 | "budgets": [
47 | {
48 | "type": "initial",
49 | "maximumWarning": "2mb",
50 | "maximumError": "5mb"
51 | },
52 | {
53 | "type": "anyComponentStyle",
54 | "maximumWarning": "6kb",
55 | "maximumError": "10kb"
56 | }
57 | ]
58 | }
59 | }
60 | },
61 | "serve": {
62 | "builder": "@angular-devkit/build-angular:dev-server",
63 | "options": {
64 | "browserTarget": "universal-starter-v9:build"
65 | },
66 | "configurations": {
67 | "production": {
68 | "browserTarget": "universal-starter-v9:build:production"
69 | }
70 | }
71 | },
72 | "extract-i18n": {
73 | "builder": "@angular-devkit/build-angular:extract-i18n",
74 | "options": {
75 | "browserTarget": "universal-starter-v9:build"
76 | }
77 | },
78 | "test": {
79 | "builder": "@angular-devkit/build-angular:karma",
80 | "options": {
81 | "main": "src/test.ts",
82 | "polyfills": "src/polyfills.ts",
83 | "tsConfig": "tsconfig.spec.json",
84 | "karmaConfig": "karma.conf.js",
85 | "assets": ["src/favicon.ico", "src/assets"],
86 | "styles": ["src/styles.css"],
87 | "scripts": []
88 | }
89 | },
90 | "lint": {
91 | "builder": "@angular-devkit/build-angular:tslint",
92 | "options": {
93 | "tsConfig": [
94 | "tsconfig.app.json",
95 | "tsconfig.spec.json",
96 | "e2e/tsconfig.json"
97 | ],
98 | "exclude": ["**/node_modules/**"]
99 | }
100 | },
101 | "e2e": {
102 | "builder": "@angular-devkit/build-angular:protractor",
103 | "options": {
104 | "protractorConfig": "e2e/protractor.conf.js",
105 | "devServerTarget": "universal-starter-v9:serve"
106 | },
107 | "configurations": {
108 | "production": {
109 | "devServerTarget": "universal-starter-v9:serve:production"
110 | }
111 | }
112 | },
113 | "server": {
114 | "builder": "@angular-devkit/build-angular:server",
115 | "options": {
116 | "outputPath": "dist/universal-starter-v9/server",
117 | "main": "server.ts",
118 | "tsConfig": "tsconfig.server.json",
119 | "externalDependencies": [
120 | "@nestjs/microservices",
121 | "@nestjs/microservices/microservices-module",
122 | "@nestjs/websockets",
123 | "@nestjs/websockets/socket-module",
124 | "cache-manager"
125 | ]
126 | },
127 | "configurations": {
128 | "production": {
129 | "outputHashing": "media",
130 | "fileReplacements": [
131 | {
132 | "replace": "src/environments/environment.ts",
133 | "with": "src/environments/environment.prod.ts"
134 | }
135 | ],
136 | "sourceMap": false,
137 | "optimization": false
138 | }
139 | }
140 | },
141 | "serve-ssr": {
142 | "builder": "@nguniversal/builders:ssr-dev-server",
143 | "options": {
144 | "browserTarget": "universal-starter-v9:build",
145 | "serverTarget": "universal-starter-v9:server"
146 | },
147 | "configurations": {
148 | "production": {
149 | "browserTarget": "universal-starter-v9:build:production",
150 | "serverTarget": "universal-starter-v9:server:production"
151 | }
152 | }
153 | },
154 | "prerender": {
155 | "builder": "@nguniversal/builders:prerender",
156 | "options": {
157 | "browserTarget": "universal-starter-v9:build:production",
158 | "serverTarget": "universal-starter-v9:server:production",
159 | "routes": ["/"]
160 | },
161 | "configurations": {
162 | "production": {}
163 | }
164 | }
165 | }
166 | }
167 | },
168 | "defaultProject": "universal-starter-v9",
169 | "cli": {
170 | "analytics": false
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/browserslist:
--------------------------------------------------------------------------------
1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
2 | # For additional information regarding the format and rule options, please see:
3 | # https://github.com/browserslist/browserslist#queries
4 |
5 | # You can see what browsers were selected by your queries by running:
6 | # npx browserslist
7 |
8 | > 0.5%
9 | last 2 versions
10 | Firefox ESR
11 | not dead
12 | not IE 9-11 # For IE 9-11 support, remove 'not'.
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration file, see link for more information
2 | // https://karma-runner.github.io/1.0/config/configuration-file.html
3 |
4 | module.exports = function (config) {
5 | config.set({
6 | basePath: '',
7 | frameworks: ['jasmine', '@angular-devkit/build-angular'],
8 | plugins: [
9 | require('karma-jasmine'),
10 | require('karma-chrome-launcher'),
11 | require('karma-jasmine-html-reporter'),
12 | require('karma-coverage-istanbul-reporter'),
13 | require('@angular-devkit/build-angular/plugins/karma')
14 | ],
15 | client: {
16 | clearContext: false // leave Jasmine Spec Runner output visible in browser
17 | },
18 | coverageIstanbulReporter: {
19 | dir: require('path').join(__dirname, './coverage/universal-starter-v9'),
20 | reports: ['html', 'lcovonly', 'text-summary'],
21 | fixWebpackSourcePaths: true
22 | },
23 | reporters: ['progress', 'kjhtml'],
24 | port: 9876,
25 | colors: true,
26 | logLevel: config.LOG_INFO,
27 | autoWatch: true,
28 | browsers: ['Chrome'],
29 | singleRun: false,
30 | restartOnFileChange: true
31 | });
32 | };
33 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "universal-starter-v9",
3 | "version": "0.1.0",
4 | "license": "MIT",
5 | "repository": {
6 | "type": "git",
7 | "url": "https://github.com/angular/universal-starter.git"
8 | },
9 | "contributors": [
10 | "AngularClass ",
11 | "PatrickJS ",
12 | "Jeff Whelpley ",
13 | "Jeff Cross ",
14 | "Mark Pieszak ",
15 | "Jason Jean ",
16 | "Fabian Wiles ",
17 | "Kamil Mysliwiec ",
18 | "Michael Prentice "
19 | ],
20 | "scripts": {
21 | "ng": "ng",
22 | "start": "ng serve",
23 | "build": "ng build",
24 | "test": "ng test",
25 | "lint": "ng lint",
26 | "e2e": "ng e2e",
27 | "dev:ssr": "ng run universal-starter-v9:serve-ssr",
28 | "serve:ssr": "node dist/universal-starter-v9/server/main.js",
29 | "prebuild:ssr": "ngcc",
30 | "build:ssr": "ng build --prod && ng run universal-starter-v9:server:production",
31 | "prerender": "ng run universal-starter-v9:prerender"
32 | },
33 | "pre-commit": [],
34 | "private": true,
35 | "dependencies": {
36 | "@angular/animations": "~9.0.0",
37 | "@angular/common": "~9.0.0",
38 | "@angular/compiler": "~9.0.0",
39 | "@angular/core": "~9.0.0",
40 | "@angular/forms": "~9.0.0",
41 | "@angular/platform-browser": "~9.0.0",
42 | "@angular/platform-browser-dynamic": "~9.0.0",
43 | "@angular/platform-server": "~9.0.0",
44 | "@angular/router": "~9.0.0",
45 | "@nestjs/common": "^6.11.6",
46 | "@nestjs/core": "^6.11.6",
47 | "@nestjs/ng-universal": "^3.0.0",
48 | "@nestjs/platform-express": "^6.11.6",
49 | "@nguniversal/common": "9.0.0",
50 | "@nguniversal/express-engine": "9.0.0",
51 | "class-transformer": "^0.2.3",
52 | "class-validator": "^0.9.1",
53 | "classlist.js": "1.1.20150312",
54 | "core-js": "^2.6.5",
55 | "rxjs": "~6.5.2",
56 | "terser": "^4.1.2",
57 | "tsconfig-paths": "^3.8.0",
58 | "tslib": "^1.10.0",
59 | "webpack-cli": "3.3.6",
60 | "zone.js": "~0.9.1"
61 | },
62 | "devDependencies": {
63 | "@angular-devkit/build-angular": "~0.900.1",
64 | "@angular/cli": "~9.0.1",
65 | "@angular/compiler-cli": "~9.0.0",
66 | "@angular/language-service": "~9.0.0",
67 | "@nguniversal/builders": "^9.0.0",
68 | "@types/jasmine": "~3.5.3",
69 | "@types/jasminewd2": "~2.0.8",
70 | "@types/node": "~13.7.0",
71 | "codelyzer": "^5.2.1",
72 | "cpy-cli": "2.0.0",
73 | "express": "4.17.1",
74 | "http-server": "0.12.1",
75 | "jasmine-core": "~3.4.0",
76 | "jasmine-spec-reporter": "~4.2.1",
77 | "karma": "~4.4.1",
78 | "karma-chrome-launcher": "~3.1.0",
79 | "karma-coverage-istanbul-reporter": "~2.1.1",
80 | "karma-jasmine": "~3.1.0",
81 | "karma-jasmine-html-reporter": "^1.5.2",
82 | "mini-css-extract-plugin": "^0.9.0",
83 | "nodemon": "^2.0.2",
84 | "pre-commit": "1.2.2",
85 | "protractor": "~5.4.3",
86 | "reflect-metadata": "0.1.13",
87 | "ts-loader": "6.2.1",
88 | "ts-node": "~8.6.2",
89 | "tslint": "~6.0.0",
90 | "typescript": "^3.7.5",
91 | "wait-on": "^4.0.0"
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/server.ts:
--------------------------------------------------------------------------------
1 | import 'zone.js/dist/zone-node';
2 | import './server/main';
3 | export * from './src/main.server';
4 |
--------------------------------------------------------------------------------
/server/app.controller.ts:
--------------------------------------------------------------------------------
1 | import { Controller, Get } from '@nestjs/common';
2 |
3 | @Controller()
4 | export class AppController {
5 | @Get('api/speakers')
6 | findAllSpeakers(): any[] {
7 | return [
8 | {
9 | name: 'Name Dudeman',
10 | talk: 'Angular for your face',
11 | image: 'http://via.placeholder.com/50x50'
12 | },
13 | {
14 | name: 'Some Person',
15 | talk: 'High-five typescript',
16 | image: 'http://via.placeholder.com/50x50'
17 | },
18 | {
19 | name: 'Samwise Gamgee',
20 | talk: 'Lord of the Angular',
21 | image: 'http://via.placeholder.com/50x50'
22 | }
23 | ];
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/server/app.module.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { AngularUniversalModule } from '@nestjs/ng-universal';
3 | import { join } from 'path';
4 | import { AppServerModule } from '../src/main.server';
5 | import { AppController } from './app.controller';
6 |
7 | @Module({
8 | imports: [
9 | AngularUniversalModule.forRoot({
10 | bootstrap: AppServerModule,
11 | viewsPath: join(process.cwd(), 'dist/universal-starter-v9/browser')
12 | })
13 | ],
14 | controllers: [AppController]
15 | })
16 | export class ApplicationModule {}
17 |
--------------------------------------------------------------------------------
/server/main.ts:
--------------------------------------------------------------------------------
1 | import { NestFactory } from '@nestjs/core';
2 | import { ApplicationModule } from './app.module';
3 |
4 | async function bootstrap() {
5 | const app = await NestFactory.create(ApplicationModule);
6 | app.enableCors({
7 | methods: 'GET',
8 | maxAge: 3600
9 | });
10 | await app.listen(process.env.PORT || 4000);
11 | }
12 |
13 | // Webpack will replace 'require' with '__webpack_require__'
14 | // '__non_webpack_require__' is a proxy to Node 'require'
15 | // The below code is to ensure that the server is run only when not requiring the bundle.
16 | declare const __non_webpack_require__: NodeRequire;
17 | const mainModule = __non_webpack_require__.main;
18 | const moduleFilename = (mainModule && mainModule.filename) || '';
19 | if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
20 | bootstrap().catch(err => console.error(err));
21 | }
22 |
--------------------------------------------------------------------------------
/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-root',
5 | template: `
6 |
7 |
NestJS + Angular Universal
8 |
9 |
13 |
14 |
15 |
16 |
17 | `,
18 | styles: [
19 | `
20 | #navigation {
21 | margin: 20px 0;
22 | font-weight: bold;
23 | font-size: 18px;
24 | }
25 | #navigation a {
26 | color: #5279a4;
27 | margin-right: 20px;
28 | }
29 | #outlet-wrapper {
30 | padding: 20px;
31 | border: 1px #ccc solid;
32 | }
33 | `
34 | ]
35 | })
36 | export class AppComponent {}
37 |
--------------------------------------------------------------------------------
/src/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import { HttpClientModule } from '@angular/common/http';
2 | import { NgModule } from '@angular/core';
3 | import { BrowserModule } from '@angular/platform-browser';
4 | import { RouterModule } from '@angular/router';
5 | import { TransferHttpCacheModule } from '@nguniversal/common';
6 | import { AppComponent } from './app.component';
7 | import { HomeComponent } from './components/home/home.component';
8 | import { SharedModule } from './modules/shared/shared.module';
9 |
10 | @NgModule({
11 | declarations: [AppComponent, HomeComponent],
12 | imports: [
13 | HttpClientModule,
14 | // Add .withServerTransition() to support Universal rendering.
15 | // The application ID can be any identifier which is unique on
16 | // the page.
17 | BrowserModule.withServerTransition({ appId: 'my-app' }),
18 | TransferHttpCacheModule,
19 |
20 | RouterModule.forRoot([
21 | { path: '', component: HomeComponent, pathMatch: 'full' },
22 | {
23 | path: 'speakers',
24 | loadChildren: () =>
25 | import('./modules/speakers/speakers.module').then(
26 | m => m.SpeakersModule
27 | )
28 | }
29 | ]),
30 | SharedModule
31 | ],
32 | bootstrap: [AppComponent]
33 | })
34 | export class AppModule {}
35 |
--------------------------------------------------------------------------------
/src/app/app.server.module.ts:
--------------------------------------------------------------------------------
1 | import { HTTP_INTERCEPTORS } from "@angular/common/http";
2 | import { NgModule } from "@angular/core";
3 | import {
4 | ServerModule,
5 | ServerTransferStateModule
6 | } from "@angular/platform-server";
7 | import { AppComponent } from "./app.component";
8 | import { AppModule } from "./app.module";
9 | import { UniversalInterceptorService } from "./modules/shared/interceptors/universal-interceptor.service";
10 |
11 | @NgModule({
12 | imports: [
13 | // The AppServerModule should import your AppModule followed
14 | // by the ServerModule from @angular/platform-server.
15 | AppModule,
16 | ServerModule,
17 | ServerTransferStateModule
18 | ],
19 | // Since the bootstrapped component is not inherited from your
20 | // imported AppModule, it needs to be repeated here.
21 | bootstrap: [AppComponent],
22 | providers: [
23 | {
24 | provide: HTTP_INTERCEPTORS,
25 | useClass: UniversalInterceptorService,
26 | multi: true // <-- important (you can have many interceptors)
27 | }
28 | ]
29 | })
30 | export class AppServerModule {}
31 |
--------------------------------------------------------------------------------
/src/app/components/home/home.component.ts:
--------------------------------------------------------------------------------
1 | import { isPlatformBrowser } from '@angular/common';
2 | import { Component, Inject, OnInit, PLATFORM_ID } from '@angular/core';
3 |
4 | @Component({
5 | selector: 'home',
6 | template: `
7 | Example
8 |
9 |
Homepage (show if browser render)
10 |
11 | `,
12 | styles: [
13 | `
14 | .container {
15 | margin: 16px;
16 | padding: 16px;
17 | border: 1px black solid;
18 | }
19 | `
20 | ]
21 | })
22 | export class HomeComponent implements OnInit {
23 | public title: string;
24 | public isBrowser: boolean = isPlatformBrowser(this.platformId);
25 |
26 | constructor(@Inject(PLATFORM_ID) private platformId: Object) {}
27 |
28 | ngOnInit() {
29 | this.title = `This is the Homepage!`;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/app/interfaces/speakers.interface.ts:
--------------------------------------------------------------------------------
1 | export interface Speaker {
2 | name: string;
3 | talk: string;
4 | image: string;
5 | }
6 |
--------------------------------------------------------------------------------
/src/app/modules/shared/interceptors/universal-interceptor.service.ts:
--------------------------------------------------------------------------------
1 | import {
2 | HttpHandler,
3 | HttpInterceptor,
4 | HttpRequest
5 | } from '@angular/common/http';
6 | import { Inject, Injectable, Optional } from '@angular/core';
7 |
8 | @Injectable()
9 | export class UniversalInterceptorService implements HttpInterceptor {
10 | constructor(@Optional() @Inject('serverUrl') protected serverUrl: string) {}
11 |
12 | intercept(req: HttpRequest, next: HttpHandler) {
13 | console.log(`intercepting the url ${req.url}`);
14 | const serverReq = !this.serverUrl
15 | ? req
16 | : req.clone({
17 | url: `${this.serverUrl}${req.url}`
18 | });
19 |
20 | return next.handle(serverReq);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/app/modules/shared/shared.module.ts:
--------------------------------------------------------------------------------
1 | import { CommonModule } from '@angular/common';
2 | import { NgModule } from '@angular/core';
3 | import { UniversalInterceptorService } from './interceptors/universal-interceptor.service';
4 |
5 | @NgModule({
6 | imports: [CommonModule],
7 | providers: [UniversalInterceptorService],
8 | declarations: []
9 | })
10 | export class SharedModule {}
11 |
--------------------------------------------------------------------------------
/src/app/modules/speakers/speakers-list/speakers-list.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { Observable } from 'rxjs';
3 | import { Speaker } from '../../../interfaces/speakers.interface';
4 | import { SpeakersService } from './speakers.service';
5 |
6 | @Component({
7 | selector: 'app-speakers-list',
8 | template: `
9 | Speakers
10 |
11 | -
12 |
13 | {{ speaker.name }} - {{ speaker.talk }}
14 |
15 |
16 | `,
17 | styles: [
18 | `
19 | ul {
20 | margin: 16px;
21 | }
22 | li {
23 | display: flex;
24 | flex-direction: row;
25 | align-items: center;
26 | list-style-type: none;
27 | margin-bottom: 8px;
28 | }
29 | span {
30 | margin-left: 8px;
31 | }
32 | `
33 | ]
34 | })
35 | export class SpeakersListComponent implements OnInit {
36 | speakers: Observable;
37 |
38 | constructor(private speakersService: SpeakersService) {
39 | this.speakers = this.speakersService.getSpeakers();
40 | }
41 |
42 | ngOnInit() {}
43 | }
44 |
--------------------------------------------------------------------------------
/src/app/modules/speakers/speakers-list/speakers.service.ts:
--------------------------------------------------------------------------------
1 | import { HttpClient } from '@angular/common/http';
2 | import { Injectable } from '@angular/core';
3 | import { Speaker } from '../../../interfaces/speakers.interface';
4 |
5 | @Injectable()
6 | export class SpeakersService {
7 | constructor(private http: HttpClient) {}
8 |
9 | getSpeakers() {
10 | return this.http.get(`/api/speakers`);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/app/modules/speakers/speakers.module.ts:
--------------------------------------------------------------------------------
1 | import { CommonModule } from '@angular/common';
2 | import { NgModule } from '@angular/core';
3 | import { RouterModule } from '@angular/router';
4 | import { SharedModule } from '../shared/shared.module';
5 | import { SpeakersListComponent } from './speakers-list/speakers-list.component';
6 | import { SpeakersService } from './speakers-list/speakers.service';
7 |
8 | @NgModule({
9 | imports: [
10 | CommonModule,
11 | RouterModule.forChild([
12 | { path: '', component: SpeakersListComponent, pathMatch: 'full' }
13 | ]),
14 | SharedModule
15 | ],
16 | providers: [SpeakersService],
17 | declarations: [SpeakersListComponent]
18 | })
19 | export class SpeakersModule {}
20 |
--------------------------------------------------------------------------------
/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TrilonIO/universal-nest/1677e6a580709e077536a106c2d287f7f3f1c365/src/assets/.gitkeep
--------------------------------------------------------------------------------
/src/environments/environment.prod.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: true,
3 | prerenderUrl: 'http://localhost:4000'
4 | };
5 |
--------------------------------------------------------------------------------
/src/environments/environment.ts:
--------------------------------------------------------------------------------
1 | // The file contents for the current environment will overwrite these during build.
2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do
3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead.
4 | // The list of which env maps to which file can be found in `.angular-cli.json`.
5 |
6 | export const environment = {
7 | production: false,
8 | prerenderUrl: 'http://localhost:4000'
9 | };
10 |
--------------------------------------------------------------------------------
/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TrilonIO/universal-nest/1677e6a580709e077536a106c2d287f7f3f1c365/src/favicon.ico
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Nest + NgUniversal Demo
6 |
7 |
8 |
9 |
10 |
11 |
83 |
84 |
85 |
86 | Loading...
87 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/src/main.server.ts:
--------------------------------------------------------------------------------
1 | import { enableProdMode } from '@angular/core';
2 | import { environment } from './environments/environment';
3 |
4 | if (environment.production) {
5 | enableProdMode();
6 | }
7 |
8 | export { renderModule, renderModuleFactory } from '@angular/platform-server';
9 | export { AppServerModule } from './app/app.server.module';
10 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import { enableProdMode } from '@angular/core';
2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
3 | import { AppModule } from './app/app.module';
4 | import { environment } from './environments/environment';
5 |
6 | if (environment.production) {
7 | enableProdMode();
8 | }
9 |
10 | document.addEventListener('DOMContentLoaded', () => {
11 | platformBrowserDynamic()
12 | .bootstrapModule(AppModule)
13 | .catch(err => console.error(err));
14 | });
15 |
--------------------------------------------------------------------------------
/src/polyfills.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This file includes polyfills needed by Angular and is loaded before the app.
3 | * You can add your own extra polyfills to this file.
4 | *
5 | * This file is divided into 2 sections:
6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
8 | * file.
9 | *
10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
13 | *
14 | * Learn more in https://angular.io/guide/browser-support
15 | */
16 |
17 | /***************************************************************************************************
18 | * BROWSER POLYFILLS
19 | */
20 |
21 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */
22 | // import 'classlist.js'; // Run `npm install --save classlist.js`.
23 |
24 | /**
25 | * Web Animations `@angular/platform-browser/animations`
26 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
27 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
28 | */
29 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`.
30 |
31 | /**
32 | * By default, zone.js will patch all possible macroTask and DomEvents
33 | * user can disable parts of macroTask/DomEvents patch by setting following flags
34 | * because those flags need to be set before `zone.js` being loaded, and webpack
35 | * will put import in the top of bundle, so user need to create a separate file
36 | * in this directory (for example: zone-flags.ts), and put the following flags
37 | * into that file, and then add the following code before importing zone.js.
38 | * import './zone-flags.ts';
39 | *
40 | * The flags allowed in zone-flags.ts are listed here.
41 | *
42 | * The following flags will work for all browsers.
43 | *
44 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
45 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
46 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
47 | *
48 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
49 | * with the following flag, it will bypass `zone.js` patch for IE/Edge
50 | *
51 | * (window as any).__Zone_enable_cross_context_check = true;
52 | *
53 | */
54 |
55 | /***************************************************************************************************
56 | * Zone JS is required by default for Angular itself.
57 | */
58 | import 'zone.js/dist/zone'; // Included with Angular CLI.
59 |
60 | /***************************************************************************************************
61 | * APPLICATION IMPORTS
62 | */
63 |
--------------------------------------------------------------------------------
/src/styles.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0
4 | }
5 | body {
6 | font-family: Helvetica;
7 | }
8 | #container {
9 | max-width: 800px;
10 | margin: 0 auto;
11 | }
12 |
--------------------------------------------------------------------------------
/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "./out-tsc/app",
5 | "types": []
6 | },
7 | "files": ["src/main.ts", "src/polyfills.ts"],
8 | "include": ["src/**/*.d.ts"]
9 | }
10 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": false,
3 | "compilerOptions": {
4 | "baseUrl": "./",
5 | "outDir": "./dist/out-tsc",
6 | "sourceMap": true,
7 | "declaration": false,
8 | "downlevelIteration": true,
9 | "experimentalDecorators": true,
10 | "module": "esnext",
11 | "moduleResolution": "node",
12 | "importHelpers": true,
13 | "target": "es2015",
14 | "typeRoots": ["node_modules/@types"],
15 | "lib": ["es2018", "dom"]
16 | },
17 | "angularCompilerOptions": {
18 | "fullTemplateTypeCheck": true,
19 | "strictInjectionParameters": true
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/tsconfig.server.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.app.json",
3 | "compilerOptions": {
4 | "outDir": "./out-tsc/app-server",
5 | "module": "commonjs",
6 | "types": ["node"],
7 | "emitDecoratorMetadata": true,
8 | "experimentalDecorators": true
9 | },
10 | "files": ["src/main.server.ts", "server.ts"],
11 | "angularCompilerOptions": {
12 | "entryModule": "./src/app/app.server.module#AppServerModule"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "tslint:recommended",
3 | "rules": {
4 | "array-type": false,
5 | "arrow-parens": false,
6 | "deprecation": {
7 | "severity": "warning"
8 | },
9 | "component-class-suffix": true,
10 | "contextual-lifecycle": true,
11 | "directive-class-suffix": true,
12 | "directive-selector": [
13 | true,
14 | "attribute",
15 | "app",
16 | "camelCase"
17 | ],
18 | "component-selector": [
19 | true,
20 | "element",
21 | "app",
22 | "kebab-case"
23 | ],
24 | "import-blacklist": [
25 | true,
26 | "rxjs/Rx"
27 | ],
28 | "interface-name": false,
29 | "max-classes-per-file": false,
30 | "max-line-length": [
31 | true,
32 | 140
33 | ],
34 | "member-access": false,
35 | "member-ordering": [
36 | true,
37 | {
38 | "order": [
39 | "static-field",
40 | "instance-field",
41 | "static-method",
42 | "instance-method"
43 | ]
44 | }
45 | ],
46 | "no-consecutive-blank-lines": false,
47 | "no-console": [
48 | true,
49 | "debug",
50 | "info",
51 | "time",
52 | "timeEnd",
53 | "trace"
54 | ],
55 | "no-empty": false,
56 | "no-inferrable-types": [
57 | true,
58 | "ignore-params"
59 | ],
60 | "no-non-null-assertion": true,
61 | "no-redundant-jsdoc": true,
62 | "no-switch-case-fall-through": true,
63 | "no-var-requires": false,
64 | "object-literal-key-quotes": [
65 | true,
66 | "as-needed"
67 | ],
68 | "object-literal-sort-keys": false,
69 | "ordered-imports": false,
70 | "quotemark": [
71 | true,
72 | "single"
73 | ],
74 | "trailing-comma": false,
75 | "no-conflicting-lifecycle": true,
76 | "no-host-metadata-property": true,
77 | "no-input-rename": true,
78 | "no-inputs-metadata-property": true,
79 | "no-output-native": true,
80 | "no-output-on-prefix": true,
81 | "no-output-rename": true,
82 | "no-outputs-metadata-property": true,
83 | "template-banana-in-box": true,
84 | "template-no-negated-async": true,
85 | "use-lifecycle-interface": true,
86 | "use-pipe-transform-interface": true
87 | },
88 | "rulesDirectory": [
89 | "codelyzer"
90 | ]
91 | }
--------------------------------------------------------------------------------