Универсальный Angular используется для рендеринга html на стороне сервера и отправляет обратно в браузер. Google не может сканировать выражение привязки, указанное в метатеге. Поэтому требуется универсальный Angular. Он включает два метода.

  1. ​renderModuleFactory() использует API @angular/platform-server для предварительного рендеринга вашего приложения.
  2. @nguniversal/express-engine можно использовать в среде ExpressJS.

Начиная

В этом руководстве вы узнаете, как интегрировать ваше приложение angular-cli с angular universal, и мы используем @nguniversal/module-map-ngfactory-loader для ленивой загрузки наших маршрутов. Установите следующие зависимости.

//install the following dependencies $ npm install --save @angular/platform-server @nguniversal/module-map-ngfactory-loader ts-loader express @nguniversal/express-engine

Шаг 1: Подготовка нашего приложения к универсальному рендерингу

Сначала мы должны добавить appId в AppModule с помощью .withServerTransition(), и appId может быть предоставлена ​​любая строка, которая зависит от вас.

@NgModule({   
bootstrap: [AppComponent],  
imports: [    // Add .withServerTransition() to support Universal rendering.    // The application ID can be any identifier which is unique on    // the page. BrowserModule.withServerTransition({appId: 'my-app'}),    ...  ],})
export class AppModule {}

Далее мы собираемся создать AppServerModule, который похож на файл app.module.ts. Файл app.server.module.ts рекомендуется запускать на сервере и копировать и вставлять следующий код, представленный ниже.

Примечание. Модуль ModuleMapLoaderModule необходим для ленивой загрузки наших маршрутов при рендеринге на стороне сервера

import {NgModule} from '@angular/core';
import {ServerModule} from '@angular/platform-server';
import {ModuleMapLoaderModule} from '@nguniversal/module-map-ngfactory-loader';
import {AppModule} from './app.module';import {AppComponent} from './app.component';
@NgModule({  
    imports: [ 
       // The AppServerModule should import your AppModule followed             // by the ServerModule from @angular/platform-server. AppModule,ServerModule, ModuleMapLoaderModule // <-- *Important* to have lazy-loaded routes work ], // Since the bootstrapped component is not inherited from your // imported AppModule, it needs to be repeated here. bootstrap: [AppComponent], }) export class AppServerModule {}

Шаг 2: Создайте файл Main.server.ts и tsconfig.server.json:

Затем мы должны создать файл main.server.ts, который помещается в нашу папку src, и экспортировать AppServerModule. Экспортированный AppServerModule используется для вызова нашего файла сервера и перемещения приложения в производственный режим для более быстрой загрузки.

import {enableProdMode} from '@angular/core';export { AppServerModule } from './app/app.module.server';
enableProdMode();

Настройте ts.config.json:

Теперь просто скопируйте содержимое файла tsconfig.app.json в tsconfig.server.json, и нам нужно внести некоторые изменения в файл tsconfig.server.json. Измените цель «module» на «commonjs», добавьте код angularCompilerOptions и установите entryModule в AppServerModule Указывается символом #.

{  "extends": "../tsconfig.json",  "compilerOptions": {    "outDir": "../out-tsc/app",    "baseUrl": "./",    "module": "commonjs",    "types": []  },  "exclude": [    "test.ts",    "**/*.spec.ts"  ],  "angularCompilerOptions": {    "entryModule": "app/app.server.module#AppServerModule"  }
}

Шаг 3: Создайте наше второе приложение для сервера в .angular-cli.json​:

Angular-cli содержит массив приложений, поэтому мы должны включить новое приложение в массив и скопировать конфигурацию клиентского приложения в серверное приложение и установить платформу в качестве сервера, как показано ниже. Удалите полифиллы и установите выходной каталог «outDir»: «dist- сервер».

Примечание. Мы создали два приложения, поэтому выходным каталогом первого приложения по умолчанию является dist. Укажите другое имя каталога для сервера​

"apps": [    {      "root": "src",      "outDir": "dist",      "assets": [        "assets",        "favicon.ico"      ],      "index": "index.html",      "main": "main.ts",      "polyfills": "polyfills.ts",      "test": "test.ts",      "tsconfig": "tsconfig.app.json",      "testTsconfig": "tsconfig.spec.json",      "prefix": "cloud",      "styles": [        "styles.css"      ],      "scripts": [      ],      "environmentSource": "environments/environment.ts",      "environments": {        "dev": "environments/environment.ts",        "prod": "environments/environment.prod.ts"      }    },    {      "name":"universal",      "platform": "server",      "root": "src",      "outDir": "dist-server",      "assets": [        "assets",        "favicon.ico"      ],      "index": "index.html",      "main": "main.server.ts",      "tsconfig": "tsconfig.server.json",      "prefix": "app",      "styles": [        "styles.css"      ],      "scripts": [      ],      "environmentSource": "environments/environment.ts",      "environments": {        "dev": "environments/environment.ts",        "prod": "environments/environment.prod.ts"      }    }
]

Создайте файл Seo_service.ts. и служебный файл используется в любом месте нашего приложения, которое используется для обновления метатегов в index.html.

import { Injectable } from '@angular/core';
import { Meta, Title } from '@angular/platform-browser';
export interface SeoData {  title?: any;  description?: any;}@Injectable()export class SeoService { // This part is happended at the end of head>title private siteTitle = 'Cloud2torial';  constructor(private _title: Title, private _meta: Meta) {}  public setHeaders(data: SeoData) {    this._title.setTitle([data.title, this.siteTitle].join(' | '));      this._meta.updateTag({        content: data.description,        name: 'description'      },
);

Импортируйте SeoService в app.module.ts:

import {SeoService} from './seo_service';
@NgModule({providers: [SeoService]})

Обновите метатеги в App.component.ts:

import { Component, OnInit } from '@angular/core';
import {SeoService} from './seo_service';
@Component({  
   selector: 'cloud-root',  
   templateUrl: './app.component.html',  
   styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit{
   constructor(private _seo: SeoService) {}
   ngOnInit() {    
     this._seo.setHeaders({      
        title: 'New App',      
        discription:'App discription'    
    }) 
}

Шаг 5: Теперь переведите приложение в рабочий режим:

Создайте приложение для производства, поэтому мы указали два приложения в .angular-cli.json: первое приложение массива 0, а второе приложение будет приложением 1.

ng build --prod && ng build --prod --app 1 --output-hashing=none

Приведенная выше команда создаст папку Dist и Dist-server, и теперь работа на стороне клиента завершена! Далее нам нужно создать экспресс-сервер с angular universal.

Шаг 6: Создайте файл server.js

Теперь нам нужно создать файл server.js с фреймворком expressjs, и я использую @nguniversal/express-engine, вы также можете использовать renderModuleFactory(), который предоставляется платформой-сервером. Требуются пакеты для использования в nodejs, и теперь все маршруты отображаются и отправляются обратно в браузер.

'use strict';
require('zone.js/dist/zone-node');
require('reflect-metadata');
const express = require('express');
const ngUniversal = require('@nguniversal/express-engine');
const { provideModuleMap } = require('@nguniversal/module-map-ngfactory-loader');
const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist-server/main.bundle');
function angularRouter(req, res) {  
  res.render('index', {req, res});
}
const app = express();
app.engine('html',ngUniversal.ngExpressEngine({  
   bootstrap: AppServerModuleNgFactory,  
   providers: [provideModuleMap(LAZY_MODULE_MAP)]
}));
app.set('view engine', 'html');
app.set('views','dist');
app.use(express.static(`${__dirname}/dist`));
app.get('*', angularRouter);
app.listen(3000, () => {
 console.log('Listening on port 3000');
});

Теперь наш сервер работает на порту 3000. Вы также можете указать каждый маршрут для рендеринга в виде html, но я использую *, чтобы включить все маршруты для рендеринга.

Вывод

node server.js

Выполните следующую команду в каталоге проекта и перейдите в браузер с URL-адресом «http://localhost:3000» и нажмите Ctrl + U в браузере Chrome, чтобы увидеть отображаемый HTML.