formation 2 лет назад
Родитель
Сommit
9846e68388

+ 48 - 1
angular-client/angular.json

@@ -17,7 +17,7 @@
         "build": {
           "builder": "@angular-devkit/build-angular:browser",
           "options": {
-            "outputPath": "dist/fatboar",
+            "outputPath": "dist/fatboar/browser",
             "index": "src/index.html",
             "main": "src/main.ts",
             "polyfills": "src/polyfills.ts",
@@ -128,6 +128,53 @@
               "devServerTarget": "fatboar:serve:production"
             }
           }
+        },
+        "server": {
+          "builder": "@angular-devkit/build-angular:server",
+          "options": {
+            "outputPath": "dist/fatboar/server",
+            "main": "server.ts",
+            "tsConfig": "tsconfig.server.json"
+          },
+          "configurations": {
+            "production": {
+              "outputHashing": "media",
+              "fileReplacements": [
+                {
+                  "replace": "src/environments/environment.ts",
+                  "with": "src/environments/environment.prod.ts"
+                }
+              ],
+              "sourceMap": false,
+              "optimization": true
+            }
+          }
+        },
+        "serve-ssr": {
+          "builder": "@nguniversal/builders:ssr-dev-server",
+          "options": {
+            "browserTarget": "fatboar:build",
+            "serverTarget": "fatboar:server"
+          },
+          "configurations": {
+            "production": {
+              "browserTarget": "fatboar:build:production",
+              "serverTarget": "fatboar:server:production"
+            }
+          }
+        },
+        "prerender": {
+          "builder": "@nguniversal/builders:prerender",
+          "options": {
+            "browserTarget": "fatboar:build:production",
+            "serverTarget": "fatboar:server:production",
+            "routes": [
+              "/"
+            ]
+          },
+          "configurations": {
+            "production": {}
+          }
         }
       }
     }

Разница между файлами не показана из-за своего большого размера
+ 12406 - 27587
angular-client/package-lock.json


+ 10 - 2
angular-client/package.json

@@ -8,7 +8,11 @@
     "test": "ng test",
     "lint": "ng lint",
     "e2e": "ng e2e",
-    "test-ci": "ng test --karma-config=karma-ci.conf.js --no-progress"
+    "test-ci": "ng test --karma-config=karma-ci.conf.js --no-progress",
+    "dev:ssr": "ng run fatboar:serve-ssr",
+    "serve:ssr": "node dist/fatboar/server/main.js",
+    "build:ssr": "ng build --prod && ng run fatboar:server:production",
+    "prerender": "ng run fatboar:prerender"
   },
   "private": true,
   "dependencies": {
@@ -22,6 +26,7 @@
     "@angular/material": "^9.2.2",
     "@angular/platform-browser": "~9.1.4",
     "@angular/platform-browser-dynamic": "~9.1.4",
+    "@angular/platform-server": "~9.1.4",
     "@angular/router": "~9.1.4",
     "@nguniversal/express-engine": "^9.1.1",
     "@nguniversal/module-map-ngfactory-loader": "^8.2.6",
@@ -29,6 +34,7 @@
     "@types/leaflet": "^1.9.0",
     "bootstrap": "^4.6.2",
     "chart.js": "^2.9.4",
+    "express": "^4.15.2",
     "jwt-decode": "^2.2.0",
     "karma-coverage": "^2.2.0",
     "karma-firefox-launcher": "^1.3.0",
@@ -40,7 +46,7 @@
     "saturn-datepicker": "^8.0.5",
     "ts-loader": "^9.4.2",
     "tslib": "^1.14.1",
-    "zone.js": "^0.11.8"
+    "zone.js": "^0.10.3"
   },
   "devDependencies": {
     "@angular-devkit/build-angular": "^0.901.4",
@@ -48,6 +54,8 @@
     "@angular/compiler-cli": "~9.1.4",
     "@angular/language-service": "~9.1.4",
     "@ngtools/webpack": "^15.1.6",
+    "@nguniversal/builders": "^9.1.1",
+    "@types/express": "^4.17.0",
     "@types/jasmine": "^3.5.14",
     "@types/jasminewd2": "^2.0.10",
     "@types/node": "^12.20.55",

+ 60 - 0
angular-client/server.ts

@@ -0,0 +1,60 @@
+import 'zone.js/dist/zone-node';
+
+import { ngExpressEngine } from '@nguniversal/express-engine';
+import * as express from 'express';
+import { join } from 'path';
+
+import { AppServerModule } from './src/main.server';
+import { APP_BASE_HREF } from '@angular/common';
+import { existsSync } from 'fs';
+
+// The Express app is exported so that it can be used by serverless Functions.
+export function app() {
+  const server = express();
+  const distFolder = join(process.cwd(), 'dist/fatboar/browser');
+  const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index';
+
+  // Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
+  server.engine('html', ngExpressEngine({
+    bootstrap: AppServerModule,
+  }));
+
+  server.set('view engine', 'html');
+  server.set('views', distFolder);
+
+  // Example Express Rest API endpoints
+  // server.get('/api/**', (req, res) => { });
+  // Serve static files from /browser
+  server.get('*.*', express.static(distFolder, {
+    maxAge: '1y'
+  }));
+
+  // All regular routes use the Universal engine
+  server.get('*', (req, res) => {
+    res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] });
+  });
+
+  return server;
+}
+
+function run() {
+  const port = process.env.PORT || 4000;
+
+  // Start up the Node server
+  const server = app();
+  server.listen(port, () => {
+    console.log(`Node Express server listening on http://localhost:${port}`);
+  });
+}
+
+// Webpack will replace 'require' with '__webpack_require__'
+// '__non_webpack_require__' is a proxy to Node 'require'
+// The below code is to ensure that the server is run only when not requiring the bundle.
+declare const __non_webpack_require__: NodeRequire;
+const mainModule = __non_webpack_require__.main;
+const moduleFilename = mainModule && mainModule.filename || '';
+if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
+  run();
+}
+
+export * from './src/main.server';

+ 3 - 1
angular-client/src/app/app-routing.module.ts

@@ -45,7 +45,9 @@ const routes: Routes = [
 ];
 
 @NgModule({
-  imports: [RouterModule.forRoot(routes)],
+  imports: [RouterModule.forRoot(routes, {
+    initialNavigation: 'enabled'
+})],
   exports: [RouterModule]
 })
 export class AppRoutingModule { }

+ 1 - 1
angular-client/src/app/app.module.ts

@@ -111,7 +111,7 @@ import { TirageComponent } from './components/auth/tirage/tirage.component';
     
   ],
   imports: [
-    BrowserModule,
+    BrowserModule.withServerTransition({ appId: 'serverApp' }),
     AppRoutingModule,
     BrowserAnimationsModule,
     HttpClientModule,

+ 14 - 0
angular-client/src/app/app.server.module.ts

@@ -0,0 +1,14 @@
+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 {}

+ 10 - 0
angular-client/src/main.server.ts

@@ -0,0 +1,10 @@
+import { enableProdMode } from '@angular/core';
+
+import { environment } from './environments/environment';
+
+if (environment.production) {
+  enableProdMode();
+}
+
+export { AppServerModule } from './app/app.server.module';
+export { renderModule, renderModuleFactory } from '@angular/platform-server';

+ 3 - 1
angular-client/src/main.ts

@@ -8,5 +8,7 @@ if (environment.production) {
   enableProdMode();
 }
 
-platformBrowserDynamic().bootstrapModule(AppModule)
+document.addEventListener('DOMContentLoaded', () => {
+     platformBrowserDynamic().bootstrapModule(AppModule)
   .catch(err => console.error(err));
+   });

+ 17 - 0
angular-client/tsconfig.server.json

@@ -0,0 +1,17 @@
+{
+  "extends": "./tsconfig.app.json",
+  "compilerOptions": {
+    "outDir": "./out-tsc/app-server",
+    "module": "commonjs",
+    "types": [
+      "node"
+    ]
+  },
+  "files": [
+    "src/main.server.ts",
+    "server.ts"
+  ],
+  "angularCompilerOptions": {
+    "entryModule": "./src/app/app.server.module#AppServerModule"
+  }
+}