Отображение на стороне сервера с помощью Angular4 (Angular Universal)

Я работаю над проектом Angular4 webpack, в который я хотел добавить AngularUniversal, чтобы сделать возможной поддержку на стороне сервера. Но большинство руководств используют angular cli.I хочу интегрировать Universal с webpack.I пробовал после этого учебник без везения. Может кто-то помогите.

Ответы

Ответ 1

Этот Angular Universal предназначен только для Angular 2. Если вы хотите начать с нуля, вы можете использовать это Angular 4 Universal Seed, который имеет все функции, такие как:

  • Angular 4
  • WebPack
  • dev/prod
  • Компиляция SCSS
  • i18n, SEO и TSLint/codelyzer
  • lazy loading, config, cache

Или если у вас уже есть проект Angular 4, вы можете интегрировать Universal, выполнив следующие настройки в своем коде:

Установить эти пакеты:
npm install @angular/{common,compiler,compiler-cli,core,forms,http,platform-browser,platform-browser-dynamic,platform-server,router,animations}@latest [email protected] --save

npm install express @types/express --save-dev

Добавьте это в свой файл app.module.ts

import { BrowserModule } from '@angular/platform-browser';
BrowserModule.withServerTransition({
  appId: 'my-app-id'   // withServerTransition is available only in Angular 4
}),

Создать следующие файлы

ЦСИ/уни/app.server.ts

import { NgModule } from '@angular/core';
import { APP_BASE_HREF } from '@angular/common';
import { ServerModule } from '@angular/platform-server';
import { AppComponent } from '../app/app';
import { AppModule } from '../app/app.module';
import 'reflect-metadata';
import 'zone.js';
@NgModule({
  imports: [
    ServerModule,
    AppModule
  ],
  bootstrap: [
    AppComponent
  ],
  providers: [
    {provide: APP_BASE_HREF, useValue: '/'}
  ]
})
export class AppServerModule {
}


SRC/однотонных/сервер-uni.ts

import 'zone.js/dist/zone-node';
import 'zone.js';
import 'reflect-metadata';
import { enableProdMode } from '@angular/core';
import { AppServerModuleNgFactory } from  '../../aot/src/uni/app.server.ngfactory';
import * as express from 'express';
import { ngUniversalEngine } from './universal-engine';
enableProdMode();
const server = express();
// set our angular engine as the handler for html files, so it will be used to render them.
server.engine('html', ngUniversalEngine({
    bootstrap: [AppServerModuleNgFactory]
}));
// set default view directory
server.set('views', 'src');
// handle requests for routes in the app.  ngExpressEngine does the rendering.
server.get(['/', '/dashboard', '/heroes', '/detail/:id'], (req:any, res:any) => {
    res.render('index.html', {req});
});
// handle requests for static files
server.get(['/*.js', '/*.css'], (req:any, res:any, next:any) => {
    let fileName: string = req.originalUrl;
    console.log(fileName);
    let root = fileName.startsWith('/node_modules/') ? '.' : 'src';
    res.sendFile(fileName, { root: root }, function (err:any) {
        if (err) {
            next(err);
        }
    });
});
// start the server
server.listen(3200, () => {
    console.log('listening on port 3200...');
});

ЦСИ/уни/УНИВЕРСАЛ-engine.ts

import * as fs from 'fs';
import { renderModuleFactory } from '@angular/platform-server';
const templateCache = {}; // cache for page templates
const outputCache = {};   // cache for rendered pages
export function ngUniversalEngine(setupOptions: any) {
  return function (filePath: string, options: { req: Request }, callback: (err: Error, html: string) => void) {
    let url: string = options.req.url;
    let html: string = outputCache[url];
    if (html) {
      // return already-built page for this url
      console.log('from cache: ' + url);
      callback(null, html);
      return;
    }
    console.log('building: ' + url);
    if (!templateCache[filePath]) {
      let file = fs.readFileSync(filePath);
      templateCache[filePath] = file.toString();
    }
    // render the page via angular platform-server
    let appModuleFactory = setupOptions.bootstrap[0];
    renderModuleFactory(appModuleFactory, {
      document: templateCache[filePath],
      url: url
    }).then(str => {
      outputCache[url] = str;
      callback(null, str);
    });
  };
}

Добавьте конфигурацию ниже в файл tsconfig.ts, который, как я полагаю, расположен в корневом каталоге

{
    "compilerOptions": {
        "baseUrl": "",
        "declaration": false,
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "lib": ["es2016", "dom"],
        "moduleResolution": "node",
        "outDir": "./dist/out-tsc",
        "sourceMap": true,
        "target": "es5",
        "module": "commonjs",
        "types": ["node"],
        "typeRoots": [
            "node_modules/@types"
        ]
    },
    "files": [
        "src/uni/app.server.ts",
        "src/uni/server-uni.ts"
    ],
    "angularCompilerOptions": {
        "genDir": "aot",
        "entryModule": "./src/app/app.module#AppModule",
        "skipMetadataEmit": true
    },
    "exclude": [
        "test.ts",
        "**/*.spec.ts"
    ]
}

Atlast webpack.config.uni.js в корневом каталоге

const ngtools = require('@ngtools/webpack');
const webpack = require('webpack');
const path = require('path');
const ExtractTextWebpackPlugin = require("extract-text-webpack-plugin");
module.exports = {
    devtool: 'source-map',
    entry: {
        main: ['./src/uni/app.server.ts', './src/uni/server-uni.ts']
    },
    resolve: {
        extensions: ['.ts', '.js']
    },
    target: 'node',
    output: {
        path: path.join(__dirname, "dist"),
        filename: 'server.js'
    },
    plugins: [
        new ngtools.AotPlugin({
            tsConfigPath: './tsconfig.json'
        })
    ],
    module: {
        rules: [
            {
                test: /\.(scss|html|png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
                use: 'raw-loader'
            },
            { test: /\.ts$/,  loader: require.resolve('@ngtools/webpack') },
            {
                test: /\.(png|jpg|woff|woff2|eot|ttf|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
                loader: 'url?limit=512&&name=[path][name].[ext]?[hash]'
            },
            { test: /\.scss$/, use: [{
                loader: "style-loader" // creates style nodes from JS strings
            }, {
                loader: "css-loader" // translates CSS into CommonJS
            }, {
                loader: "sass-loader" // compiles Sass to CSS
            }] }
        ]
    }
}

Добавьте ниже скриптов в файл package.json:

"ngc-build": "ngc -p ./tsconfig.json", // To generate ngFactory file
"build:uni": "webpack --config webpack.config.uni.js",
"serve:uni": "node dist/server.js",

Есть определенные вещи, которые мы должны иметь в виду:

  • window, document, navigator и другие типы браузеров - не существует на сервере - поэтому использование их или любая библиотека, которая их использует (например, jQuery) не будет работать. У вас есть некоторые опции, приведенные в этой ссылке, если вам действительно нужна часть этой функции.

Ответ 2

Angular universal используется только для angular 2.x. angular 4.x вам необходимо использовать платформу server.Examples следующие:

Для angular 2.X.X:

Проект семян AngularClass с использованием express/universal

https://github.com/angular/universal-starter

Для angular 4.X.X Используйте сервер платформы angular

https://github.com/ng-seed/universal

Есть еще несколько примеров:

Ответ 3

Пример, упомянутый в данном учебнике, - это пример, упомянутый в разделе Angular Resources. Недавно они обновили свои документы и еще не предоставили подробную документацию для реализации @angular/universal. Это была страница, которую вы искали, но у нее были некоторые проблемы, упомянутые . Может быть, поэтому они удалили его и решили переписать его.

Ответ 4

Вы можете найти учебник Angular 4 на серверном рендеринге с помощью Webpack на в этом блоге.

Особенности:

  • он построен на Angular 4
  • он не зависит от Angular CLI
  • он основывается на Webpack
  • блог предоставляет пошаговую инструкцию в три этапа:
    • Этап 1: Запустите страницу приветствия Hello Server на контейнере Docker (я предоставляю предустановленное изображение Docker для вашего удобства, но инструкции должны работать в вашей собственной среде Angular).
    • Этап 2. Создайте новую функциональную ссылку на главной странице
    • фаза 3 (необязательно): динамическая вставка WordPress Blog POST через RESTful API

Конечный результат можно легко просмотреть на хосте Docker, например:

(dockerhost)$ docker run -it -p 8002:8000 oveits/angular_hello_world:centos bash
(container)# git clone https://github.com/oveits/ng-universal-demo
(container)# cd ng-universal-demo
(container)# npm i
(container)# npm run start

Я выбрал порт 8002 выше, так как я запускаю другие примеры на портах 8000 и 8001; Если хост-докер запущен на Virtualbox, вам может понадобиться сопоставление портов с 8002 узла Virtualbox на 8002 виртуальной виртуальной машины.

В браузере перейдите к http://localhost:8002/blog. Вы увидите содержимое сообщения в блоге, которое загружается из Wordpress API. С правой кнопкой мыши → источник просмотра вы увидите HTML-контент. Это демонстрирует, что это страница на стороне сервера.

PS: Как и учебник, который вы опробовали, учебник основан на проекте Git, который первоначально был создан Робом Wormald, но с этой вилкой FrozenPandaz, я нашел версию, которая была обновлена ​​до Angular 4 и лучше работала с Webpack (см. приложение в блоге для более подробной информации).