Angular 通用获取域名:属性 'req' 在类型 'object' 上不存在

Angular Universal get domain name: Property 'req' does not exist on type 'object'

首先感谢Whosebug提供这个提问的平台,也感谢花时间帮助的人。

我在 angular 比较陌生。我有一个 angular 通用项目,有多个域指向该托管服务器,我想根据域名加载不同的内容。所以我需要在 angular 组件中获取域名。

我试过,但是当我添加以下代码时出现错误:

app.engine('html', (_, options, callback) => {
let engine = ngExpressEngine({
    bootstrap: AppServerModuleNgFactory,
    providers: [
        { provide: 'request', useFactory: () => options.req, deps: [] },
        provideModuleMap(LAZY_MODULE_MAP)
    ]
});
engine(_, options, callback);

});

我的错误是

TS2339: Property 'req' does not exist on type 'object'.

Property 'req' does not exist on type 'object'.ts(2339)

'object' 类型的参数不能分配给 'RenderOptions' 类型的参数。 类型“{}”缺少类型 'RenderOptions' 中的以下属性:req、bootstrapts(2345)

我的问题是如何使 options.req 起作用?我不知道我是否遗漏了任何依赖项或其他内容?

server.ts:

import 'zone.js/dist/zone-node';
import {enableProdMode} from '@angular/core';
// Express Engine
import {ngExpressEngine} from '@nguniversal/express-engine';
// Import module map for lazy loading
import {provideModuleMap} from '@nguniversal/module-map-ngfactory-loader';

import * as express from 'express';
import {join} from 'path';

// Faster server renders w/ Prod mode (dev mode never needed)
enableProdMode();

// Express server
export const app = express();

const PORT = process.env.PORT || 4000;
const DIST_FOLDER = join(process.cwd(), 'dist/browser');

// * NOTE :: leave this as require() since this file is built Dynamically from webpack
const {AppServerModuleNgFactory, LAZY_MODULE_MAP} =  require('./dist/server/main');


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

app.engine('html', (_, options, callback) => {
  let engine = ngExpressEngine({
      bootstrap: AppServerModuleNgFactory,
      providers: [
          { provide: 'request', useFactory: () => options.req, deps: [] },
          provideModuleMap(LAZY_MODULE_MAP)
      ]
  });
  engine(_, options, callback);
});

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

// Example Express Rest API endpoints
// app.get('/api/**', (req, res) => { });
// Serve static files from /browser
app.get('*.*', express.static(DIST_FOLDER, {
  maxAge: '1y'
}));

// All regular routes use the Universal engine
app.get('*', (req, res) => {
  res.render('index', { req });
});

package.json

{
  "name": "share-ssr-loading",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e",
    "compile:server": "webpack --config webpack.server.config.js --progress --colors",
    "serve:ssr": "node local.js",
    "build:ssr": "npm run build:client-and-server-bundles && npm run compile:server",
    "build:client-and-server-bundles": "ng build --prod && ng run wf-share-ssr:server:production",
    "server": "node local.js",
    "build:prod": "npm run build:browser:prod && npm run build:server:prod",
    "serve:prerender": "node static.js",
    "build:prerender": "npm run build:prod && node dist/prerender.js",
    "build:prod:deploy": "npm run build:prod && npm run deploy",
    "build:browser:prod": "ng build --prod",
    "build:browser:serverless": "ng build --prod --base-href /",
    "build:serverless": "npm run build:browser:serverless && npm run build:server:serverless",
    "build:serverless:deploy": "npm run build:serverless && npm run deploy",
    "deploy": "cp-cli dist/ functions/dist/ && cd functions && npm install && firebase deploy",
    "build:server:prod": "ng run wf-share-ssr:server && webpack --config webpack.server.config.js --progress --colors",
    "build:server:serverless": "ng run wf-share-ssr:server && webpack --config webpack.server.config.js --progress --colors",
    "build:server:dev": "ng run wf-share-ssr:server && webpack --config webpack.dev.server.config.js --progress --colors",
    "build:dev": "npm run build:browser:dev && npm run build:server:dev",
    "build:browser:dev": "ng build",
    "build:dev:run": "npm run build:dev && npm run server"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "~8.1.1",
    "@angular/common": "~8.1.1",
    "@angular/compiler": "~8.1.1",
    "@angular/core": "~8.1.1",
    "@angular/fire": "^5.2.1",
    "@angular/forms": "~8.1.1",
    "@angular/platform-browser": "~8.1.1",
    "@angular/platform-browser-dynamic": "~8.1.1",
    "@angular/platform-server": "~8.1.1",
    "@angular/router": "~8.1.1",
    "@ng-toolkit/serverless": "^7.1.2",
    "@ng-toolkit/universal": "^7.1.2",
    "@nguniversal/common": "0.0.0",
    "@nguniversal/express-engine": "^7.1.0",
    "@nguniversal/module-map-ngfactory-loader": "0.0.0",
    "cors": "~2.8.4",
    "cp-cli": "^1.1.0",
    "domino": "^2.1.3",
    "express": "^4.15.2",
    "firebase": "^6.3.3",
    "firebase-admin": "~8.0.0",
    "firebase-functions": "^3.2.0",
    "firebase-tools": "^7.2.1",
    "preboot": "^7.0.0",
    "rxjs": "~6.4.0",
    "scriptjs": "^2.5.9",
    "ts-loader": "^5.2.0",
    "tslib": "^1.9.0",
    "webpack-cli": "^3.1.0",
    "xmlhttprequest": "^1.8.0",
    "zone.js": "~0.9.1",
    "bootstrap": "^4.3.1"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "~0.801.1",
    "@angular/cli": "~8.1.1",
    "@angular/compiler-cli": "~8.1.1",
    "@angular/language-service": "~8.1.1",
    "@types/node": "~8.9.4",
    "@types/jasmine": "~3.3.8",
    "@types/jasminewd2": "~2.0.3",
    "codelyzer": "^5.0.0",
    "jasmine-core": "~3.4.0",
    "jasmine-spec-reporter": "~4.2.1",
    "karma": "~4.1.0",
    "karma-chrome-launcher": "~2.2.0",
    "karma-coverage-istanbul-reporter": "~2.0.1",
    "karma-jasmine": "~2.0.1",
    "karma-jasmine-html-reporter": "^1.4.0",
    "opencollective": "^1.0.3",
    "protractor": "~5.4.0",
    "ts-loader": "^5.2.0",
    "ts-node": "~7.0.0",
    "tslint": "~5.15.0",
    "typescript": "~3.4.3",
    "webpack-cli": "^3.1.0"
  }
}

webpack.dev.server.config.js

// Work around for https://github.com/angular/angular-cli/issues/7200
// change the regex to include the packages you want to exclude
const regex = /firebase\/(app|firestore)/;

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

module.exports = {
  mode: 'none',
  entry: {
    // This is our Express server for Dynamic universal
    server: './server.ts',
    prerender: './prerender.ts'
  },
  target: 'node',
  // this makes sure we include node_modules and other 3rd party libraries
  externals: [/node_modules/, function(context, request, callback) {

    // exclude firebase products from being bundled, so they will be loaded using require() at runtime.
    if(regex.test(request)) {
      return callback(null, 'commonjs ' + request);
    }
    callback();
  }],
  resolve: { extensions: ['.ts', '.js'] },
  optimization: {
    minimize: false
  },
  output: {
    libraryTarget: 'commonjs2',
    // Puts the output at the root of the dist folder
    path: path.join(__dirname, 'dist'),
    filename: '[name].js'
  },
  module: {
    rules: [
      { test: /\.ts$/, loader: 'ts-loader' },
      {
        // Mark files inside `@angular/core` as using SystemJS style dynamic imports.
        // Removing this will cause deprecation warnings to appear.
        test: /(\|\/)@angular(\|\/)core(\|\/).+\.js$/,
        parser: { system: true },
      },
    ]
  },
  plugins: [
    new webpack.ContextReplacementPlugin(
      // fixes WARNING Critical dependency: the request of a dependency is an expression
      /(.+)?angular(\|\/)core(.+)?/,
      path.join(__dirname, 'src'), // location of your src
      {} // a map of your routes
    ),
    new webpack.ContextReplacementPlugin(
      // fixes WARNING Critical dependency: the request of a dependency is an expression
      /(.+)?express(\|\/)(.+)?/,
      path.join(__dirname, 'src'),
      {}
    )
  ]
};

完整构建日志:

WARNING in ./node_modules/typescript/lib/typescript.js 94814:19-45
Critical dependency: the request of a dependency is an expression
 @ ./prerender.ts

WARNING in ./node_modules/ws/lib/BufferUtil.js
Module not found: Error: Can't resolve 'bufferutil' in 
'E:\Projects\Web\share-ssr-loading\node_modules\ws\lib'
 @ ./node_modules/ws/lib/BufferUtil.js
 @ ./node_modules/ws/lib/Receiver.js
 @ ./node_modules/ws/index.js
 @ ./server.ts

WARNING in ./node_modules/ws/lib/Validation.js
Module not found: Error: Can't resolve 'utf-8-validate' in 'E:\Projects\Web\share-ssr-loading\node_modules\ws\lib'
 @ ./node_modules/ws/lib/Validation.js
 @ ./node_modules/ws/lib/Receiver.js
 @ ./node_modules/ws/index.js
 @ ./server.ts

ERROR in E:\Projects\Web\share-ssr-loading\server.ts
./server.ts
[tsl] ERROR in E:\Projects\Web\share-ssr-loading\server.ts(39,59)
      TS2339: Property 'req' does not exist on type 'object'.

ERROR in E:\Projects\Web\share-ssr-loading\server.ts
./server.ts
[tsl] ERROR in E:\Projects\Web\share-ssr-loading\server.ts(43,13)
      TS2345: Argument of type 'object' is not assignable to parameter of type 'RenderOptions'.
  Type '{}' is missing the following properties from type 'RenderOptions': req, bootstrap
npm ERR! code ELIFECYCLE
npm ERR! errno 2
npm ERR! share-ssr-loading@0.0.0 build:server:dev: `ng run share-ssr-loading:server && webpack --config webpack.dev.server.config.js --progress --colors`
npm ERR! Exit status 2
npm ERR!
npm ERR! Failed at the share-ssr-loading@0.0.0 build:server:dev script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\dev\AppData\Roaming\npm-cache\_logs19-08-05T21_38_27_329Z-debug.log
npm ERR! code ELIFECYCLE
npm ERR! errno 2
npm ERR! share-ssr-loading@0.0.0 build:dev: `npm run build:browser:dev && npm run build:server:dev`
npm ERR! Exit status 2
npm ERR!
npm ERR! Failed at the share-ssr-loading@0.0.0 build:dev script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\dev\AppData\Roaming\npm-cache\_logs19-08-05T21_38_27_365Z-debug.log
npm ERR! code ELIFECYCLE
npm ERR! errno 2
npm ERR! share-ssr-loading@0.0.0 build:dev:run: `npm run build:dev && npm run server`
npm ERR! Exit status 2
npm ERR!
npm ERR! Failed at the share-ssr-loading@0.0.0 build:dev:run script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\dev\AppData\Roaming\npm-cache\_logs19-08-05T21_38_27_393Z-debug.log

我用的是windows 10、node v10.16.0 npm v6.9.0

谢谢

几周前我遇到了同样的问题,但一直没时间调查。

我使用的解决方法是修改 server.ts 中的声明,将 options 键入 any

app.engine('html', (_, options: any, callback)

我找到的解决方案是获取主机名(http://xxxxx.com) not http://localhost 如果您的本地代码不是 运行 则使用 this.request.get('referer');

constructor(@Optional() @Inject(REQUEST) private request: any,
    @Optional() @Inject(RESPONSE) private response: any,
    @Inject(PLATFORM_ID) private platformId: Object){
    if (isPlatformServer(this.platformId)) {
          this.referer = 'referer: ' + this.request.get('referer');
          // this.request2 = JSON.stringify(this.request);
          console.log('server this.request: ' + this.request.get('host'));
        } else {
          this.hostName = 'document.location.hostname: ' +  document.location.hostname;
          console.log( 'document.location.hostname: ' + document.location.hostname); // host on the browser
        }
}

在此解决方案中,您无需修改​​server.ts。所以在你的 server.ts 中。

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