首页 > 解决方案 > Angular Universal 在没有事件的情况下以错误的方式呈现页面

问题描述

我将此页面:https ://www.beta.rohub.org 迁移到 Angular 7,并开始使用 Angular 通用使该页面在服务器端渲染上提供服务。页面被渲染,模板工作,一些请求工作,页面看起来正常。

有些事情不起作用。

例如:

  1. 点击事件 - 不完全工作,只有按钮不工作
  2. 查看孩子
  3. 指令
  4. NgModel - 来自 ngmodel 的值在更改后不起作用
  5. 本地存储和缓存
  6. 路由 - 某些组件在转到用于显示研究对象的组件上的示例后无法初始化。
  7. 主机监听器

Dist 文件夹生成正确。

这是我的代码。我不知道这所有配置有什么问题。

角.json

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "ng-universal-demo": {
      "projectType": "application",
      "root": "",
      "sourceRoot": "src",
      "schematics": {
        "@schematics/angular:component": {
          "style": "css"
        }
      },
      "prefix": "app",
      "architect": {
        "build": {
          "builder": "@angular-builders/custom-webpack:browser",
          "options": {
            "outputPath": "dist/browser",
            "index": "src/index.html",
            "main": "src/main.browser.ts",
            "tsConfig": "tsconfig.browser.json",
            "polyfills": "src/polyfills.ts",
            "aot": true,
            "assets": [
              {
                "glob": "**/*",
                "input": "src/assets",
                "output": "/assets"
              },
              {
                "glob": "favicon.ico",
                "input": "src",
                "output": "/"
              }
            ],
            "styles": [
              "src/styles.css",
              "src/bootstrap.min.css",
              "./node_modules/ng2-tree/styles.css"
            ],
            "scripts": ["./node_modules/quill/dist/quill.min.js"],
            "customWebpackConfig": {
              "path": "./extra-webpack.config.js",
              "replaceDuplicatePlugins": true,
              "mergeStrategies": {
                "externals": "prepend"
              }
            },
            "serviceWorker": true
          },
          "configurations": {
            "production": {
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "extractCss": true,
              "namedChunks": false,
              "aot": true,
              "extractLicenses": true,
              "vendorChunk": false,
              "buildOptimizer": true,
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ]
            }
          }
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "browserTarget": "ng-universal-demo:build"
          },
          "configurations": {
            "production": {
              "browserTarget": "ng-universal-demo:build:production"
            }
          }
        },
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "browserTarget": "ng-universal-demo:build"
          }
        },
        "test": {
          "builder": "@angular-devkit/build-angular:karma",
          "options": {
            "main": "src/test.ts",
            "karmaConfig": "./karma.conf.js",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "src/tsconfig.spec.json",
            "scripts": [],
            "styles": [
              "src/styles.css"
            ],
            "assets": [
              {
                "glob": "**/*",
                "input": "src/assets",
                "output": "/assets"
              },
              {
                "glob": "favicon.ico",
                "input": "src",
                "output": "/"
              }
            ]
          }
        },
        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": [
              "src/tsconfig.app.json"
            ],
            "exclude": [
              "**/node_modules/**"
            ]
          }
        },
        "server": {
          "builder": "@angular-devkit/build-angular:server",
          "options": {
            "outputPath": "dist/server",
            "main": "src/main.server.ts",
            "tsConfig": "tsconfig.server.json"
          },
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ]
            }
          }
        }
      }
    },
    "ng-universal-demo-e2e": {
      "root": "e2e",
      "projectType": "application",
      "cli": {},
      "schematics": {},
      "architect": {
        "e2e": {
          "builder": "@angular-devkit/build-angular:protractor",
          "options": {
            "protractorConfig": "./protractor.conf.js",
            "devServerTarget": "ng-universal-demo:serve"
          }
        },
        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": [],
            "exclude": [
              "**/node_modules/**"
            ]
          }
        }
      }
    }
  },
  "cli": {},
  "schematics": {
    "@schematics/angular:class": {
      "spec": false
    },
    "@schematics/angular:component": {
      "spec": false,
      "inlineStyle": true,
      "inlineTemplate": true,
      "prefix": "app",
      "styleext": "css"
    },
    "@schematics/angular:directive": {
      "spec": false,
      "prefix": "app"
    },
    "@schematics/angular:guard": {
      "spec": false
    },
    "@schematics/angular:module": {
      "spec": false
    },
    "@schematics/angular:pipe": {
      "spec": false
    },
    "@schematics/angular:service": {
      "spec": false
    }
  }

包.json:


  "name": "ng-universal-demo",
  "version": "0.0.0",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "https://github.com/angular/universal-starter.git"
  },
  "contributors": [],
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "lint": "ng lint ng-universal-demo",
    "build:client-and-server-bundles": "ng build --prod  --output-hashing=none && ng run ng-universal-demo:server:production",
    "build:prerender": "npm run build:client-and-server-bundles && npm run compile:server && npm run generate:prerender",
    "build:ssr": "npm run build:client-and-server-bundles && npm run webpack:server",
    "compile:server": "tsc -p server.tsconfig.json",
    "webpack:server": "webpack --config webpack.server.config.js --progress --colors",
    "generate:prerender": "cd dist && node prerender",
    "serve:prerender": "cd dist/browser && http-server",
    "serve:
ssr": "node dist/server"
  },

服务器.ts

import 'zone.js/dist/zone-node';
import 'reflect-metadata';
import { enableProdMode } from '@angular/core';
import * as express from 'express';
import { join } from 'path';
import { readFileSync } from 'fs';
enableProdMode();

const app = express();
const PORT = process.env.PORT || 3000;
const DIST_FOLDER = join(process.cwd(), 'dist');

const template = readFileSync(join(DIST_FOLDER, 'browser', 'index.html')).toString();
const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require( './dist/server/main');
import { ngExpressEngine } from '@nguniversal/express-engine';
import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';

app.engine('html', ngExpressEngine({
  bootstrap: AppServerModuleNgFactory,
  providers: [
    provideModuleMap(LAZY_MODULE_MAP)
  ]
}));

app.set('view engine', 'html');
app.set('views', join(DIST_FOLDER, 'browser'));


app.get('*.*', express.static(join(DIST_FOLDER, 'browser')));

app.get('*', (req, res) => {
  res.render('index', { req });
});

app.listen(PORT, () => {
  console.log(`Node Express server listening on http://localhost:${PORT}`);
});

tsconfig.json

{
  "compileOnSave": false,
  "compilerOptions": {
    "baseUrl": "./",
    "outDir": "./dist/out-tsc",
    "sourceMap": true,
    "declaration": false,
    "module": "esnext",
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "importHelpers": true,
    "target": "es5",
    "typeRoots": [
      "node_modules/@types"
    ],
    "lib": [
      "es2017",
      "dom"
    ],
    "skipLibCheck": true
  }
}

tsconfig.app.json

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

webpack.server.config.js

var path = require('path');
var webpack = require('webpack');

module.exports = {
  entry: { server: './server.ts' },
  resolve: { extensions: ['.js', '.ts'] },
  target: 'node',
  mode: 'none',
  // this makes sure we include node_modules and other 3rd party libraries
  externals: [/node_modules/],
  output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name].js'
  },
  module: {
    rules: [{ test: /\.ts$/, loader: 'ts-loader' }]
  },
  plugins: [
    // Temporary Fix for issue: https://github.com/angular/angular/issues/11580
    // for 'WARNING Critical dependency: the request of a dependency is an expression'
    new webpack.ContextReplacementPlugin(
      /(.+)?angular(\\|\/)core(.+)?/,
      path.join(__dirname, 'src'), // location of your src
      {} // a map of your routes
    ),
    new webpack.ContextReplacementPlugin(
      /(.+)?express(\\|\/)(.+)?/,
      path.join(__dirname, 'src'),
      {}
    )
  ]
};

主服务器.ts

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

enableProdMode();


标签: angularangular7angular-universalserver-side-renderinghtml-rendering

解决方案


我解决了问题。首先是docuemnt.cookies 和window。在我的 ts 代码上。所以我通过 ngx-cookies-service 修改了 cookie,如下所示:commons.service.ts

import {CookieService} from 'ngx-cookie-service';

...

constructor(private configurationService: ConfigurationService,
              private cookies: CookieService) {

  }

....

if (name === 'accountType') {
      const cookiesArray = Object.keys(this.cookies.getAll());
      console.log(cookiesArray);
      if (cookiesArray.length >= 1) {
        console.log('COOKIES', cookiesArray, 'END OF COOKIES');
        const objectOfCookies = this.cookies.getAll(),
          arrayOfCookies = Object.keys(objectOfCookies),
          typeIndex = arrayOfCookies.indexOf(name);

        if (typeIndex !== -1) {
          const arrayOfAccounts = ['ORCID', 'GOOGLE', 'EVEREST'];
          for (const currentElement of arrayOfAccounts) {
            if (arrayOfCookies.indexOf(currentElement) !== -1) {
              this.properCookieValue = currentElement;
              break;
            }
          }
        } else {
          this.properCookieValue = null;
        }
      }
    } else {

第二件事:我的文件一切都很好,server.ts 上唯一的东西需要改变。所以 server.ts 看起来像这样:

import 'zone.js/dist/zone-node';
import 'reflect-metadata';
import { enableProdMode } from '@angular/core';
import * as express from 'express';
import * as cookieParser from 'cookie-parser';
import { join } from 'path';
import { readFileSync } from 'fs';
enableProdMode();
const domino = require('domino');
const app = express();
const PORT = process.env.PORT || 3000;
const DIST_FOLDER = join(process.cwd(), 'dist');


const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require( './dist/server/main');
import { ngExpressEngine } from '@nguniversal/express-engine';
import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';

app.engine('html', ngExpressEngine({
  bootstrap: AppServerModuleNgFactory,
  providers: [
    provideModuleMap(LAZY_MODULE_MAP)
  ]
}));


const template = readFileSync(join(DIST_FOLDER, 'browser', 'index.html')).toString();
const win = domino.createWindow(template);
global['window'] = win;
global['document'] = win.document;
app.set('view engine', 'html');
app.set('views', join(DIST_FOLDER, 'browser'));

app.use(cookieParser('Your private token'));
app.get('*.*', express.static(join(DIST_FOLDER, 'browser')));

app.get('*', (req, res) => {
  res.render('index', { req });
});

app.listen(PORT, () => {
  console.log(`Node Express server listening on http://localhost:${PORT}`);
});

推荐阅读