Angular Universal: readFile $ (...). MergeMap не является функцией - PullRequest
0 голосов
/ 21 февраля 2019

Я реализую угловую универсальную серверную визуализацию в существующее приложение angular 7.Я также пытаюсь заставить его работать с Firebase, однако в моем журнале функций в консоли Firebase я получаю следующую ошибку:

 TypeError: readFile$(...).mergeMap is not a function
    at /user_code/node_modules/angular-universal-express-firebase/node_modules/angular-universal-express/index.js:36:14
    at Layer.handle [as handle_request] (/user_code/node_modules/angular-universal-express-firebase/node_modules/express/lib/router/layer.js:95:5)
    at next (/user_code/node_modules/angular-universal-express-firebase/node_modules/express/lib/router/route.js:137:13)
    at Route.dispatch (/user_code/node_modules/angular-universal-express-firebase/node_modules/express/lib/router/route.js:112:3)
    at Layer.handle [as handle_request] (/user_code/node_modules/angular-universal-express-firebase/node_modules/express/lib/router/layer.js:95:5)
    at /user_code/node_modules/angular-universal-express-firebase/node_modules/express/lib/router/index.js:281:22
    at param (/user_code/node_modules/angular-universal-express-firebase/node_modules/express/lib/router/index.js:354:14)
    at param (/user_code/node_modules/angular-universal-express-firebase/node_modules/express/lib/router/index.js:365:14)
    at Function.process_params (/user_code/node_modules/angular-universal-express-firebase/node_modules/express/lib/router/index.js:410:3)
    at next (/user_code/node_modules/angular-universal-express-firebase/node_modules/express/lib/router/index.js:275:10)

Я настроил свой firebase.json для перенаправления всех маршрутов вфункция называется ssrApp, и когда я выполняю firebase deploy, ошибки не выдаются.Кто-нибудь имел эту проблему?

Это мой firebase.json:

{
  "hosting": {
    "public": "dist",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [
      {
        "source": "**",
        "function": "ssrApp"
      }
    ]
  },
  "functions": {
    "predeploy": "npm --prefix \"$RESOURCE_DIR\" run build"
  }
}

Это мой package.json в корневом каталоге:

{
  "name": "mse",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "build:client-app:prod": "./node_modules/.bin/ng build --prod",
    "build:server-app:prod": "./node_modules/.bin/ng run mse:server",
    "build-all": "./node_modules/.bin/npm-run-all build:client-app:prod build:server-app:prod build:functions",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e",
    "build:functions": "cd functions && npm run build",
    "move-index": "mv ./dist/index.html ./functions/lib/index-server.html",
    "firebase:serve": "firebase serve --only hosting,functions",
    "deploy": "firebase deploy",
    "start:local": "npm-run-all build-all move-index firebase:serve",
    "build-and-deploy:prod": "npm-run-all build-all move-index deploy"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "^7.2.4",
    "@angular/cdk": "^7.3.1",
    "@angular/common": "^7.2.4",
    "@angular/compiler": "^7.2.4",
    "@angular/core": "^7.2.4",
    "@angular/forms": "^7.2.4",
    "@angular/http": "^7.2.4",
    "@angular/material": "^7.3.1",
    "@angular/platform-browser": "^7.2.4",
    "@angular/platform-browser-dynamic": "^7.2.4",
    "@angular/platform-server": "^7.2.4",
    "@angular/router": "^7.2.4",
    "@nguniversal/module-map-ngfactory-loader": "^7.1.0",
    "@ngx-translate/core": "^10.0.2",
    "@ngx-translate/http-loader": "^3.0.1",
    "@types/googlemaps": "^3.30.16",
    "animate.css": "^3.7.0",
    "bootstrap": "^4.2.1",
    "compass": "^0.1.1",
    "compass-sass-mixins": "^0.12.7",
    "contentful": "^6.1.3",
    "core-js": "^2.6.4",
    "emailjs-com": "^2.3.2",
    "flag-icon-css": "^3.2.1",
    "hammerjs": "^2.0.8",
    "jquery": "^3.3.1",
    "marked": "^0.4.0",
    "ngx-bootstrap": "^3.2.0",
    "popper.js": "^1.14.7",
    "rxjs": "^6.4.0",
    "ts-loader": "^5.3.3",
    "web-animations-js": "^2.3.1",
    "webpack-cli": "^3.2.3",
    "zone.js": "^0.8.29",
    "@angular/material-moment-adapter": "7.0.0",
    "@nguniversal/express-engine": "^7.0.0",
    "express": "^4.16.2",
    "moment": "^2.22.2",
    "rxjs-compat": "^6.0.0-rc.0"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "^0.6.8",
    "@angular/cli": "~7.3.1",
    "@angular/compiler-cli": "^7.2.4",
    "@angular/language-service": "^7.2.4",
    "@types/jasmine": "^2.8.16",
    "@types/jasminewd2": "^2.0.6",
    "@types/node": "~8.9.4",
    "codelyzer": "~4.2.1",
    "jasmine-core": "~2.99.1",
    "jasmine-spec-reporter": "~4.2.1",
    "karma": "~1.7.1",
    "karma-chrome-launcher": "~2.2.0",
    "karma-coverage-istanbul-reporter": "^1.4.3",
    "karma-jasmine": "~1.1.1",
    "karma-jasmine-html-reporter": "^0.2.2",
    "protractor": "^5.4.2",
    "ts-node": "~5.0.1",
    "tslint": "~5.9.1",
    "typescript": "~3.2.4",
    "@types/express": "^4.0.39",
    "http-server": "^0.11.1",
    "karma-cli": "~1.0.1",
    "npm-run-all": "^4.1.2"
  }
}

Этоmy angular.json:

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "mse": {
      "root": "",
      "sourceRoot": "src",
      "projectType": "application",
      "prefix": "app",
      "schematics": {
        "@schematics/angular:component": {
          "styleext": "scss"
        }
      },
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "dist",
            "index": "src/index.html",
            "main": "src/main.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "src/tsconfig.app.json",
            "assets": [
              "src/favicon.ico",
              "src/assets"
            ],
            "styles": [
              "node_modules/bootstrap/dist/css/bootstrap.min.css",
              "src/styles/styles.scss",
              "src/styles/mse-theme.scss"
            ],
            "scripts": [
              "node_modules/jquery/dist/jquery.min.js",
              "node_modules/popper.js/dist/umd/popper.min.js",
              "node_modules/bootstrap/dist/js/bootstrap.min.js"
            ]
          },
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ],
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "extractCss": true,
              "namedChunks": false,
              "aot": true,
              "extractLicenses": true,
              "vendorChunk": false,
              "buildOptimizer": true
            }
          }
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "browserTarget": "mse:build"
          },
          "configurations": {
            "production": {
              "browserTarget": "mse:build:production"
            }
          }
        },
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "browserTarget": "mse:build"
          }
        },
        "test": {
          "builder": "@angular-devkit/build-angular:karma",
          "options": {
            "main": "src/test.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "src/tsconfig.spec.json",
            "karmaConfig": "src/karma.conf.js",
            "styles": [
              "styles.css"
            ],
            "scripts": [],
            "assets": [
              "src/favicon.ico",
              "src/assets"
            ]
          }
        },
        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": [
              "src/tsconfig.app.json",
              "src/tsconfig.spec.json"
            ],
            "exclude": [
              "**/node_modules/**"
            ]
          }
        },
        "server": {
          "builder": "@angular-devkit/build-angular:server",
          "options": {
            "outputPath": "functions/lib",
            "main": "src/main.server.ts",
            "tsConfig": "src/tsconfig.server.json"
          },
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ],
              "sourceMap": false,
              "optimization": {
                "scripts": false,
                "styles": true
              }
            }
          }
        }
      }
    },
    "mse-e2e": {
      "root": "e2e/",
      "projectType": "application",
      "architect": {
        "e2e": {
          "builder": "@angular-devkit/build-angular:protractor",
          "options": {
            "protractorConfig": "e2e/protractor.conf.js",
            "devServerTarget": "mse:serve"
          }
        },
        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": "e2e/tsconfig.e2e.json",
            "exclude": [
              "**/node_modules/**"
            ]
          }
        }
      }
    }
  },
  "defaultProject": "mse"
}

Это мой package.json в каталоге функций:

{
  "name": "functions",
  "scripts": {
    "build": "tsc",
    "serve": "npm run build && firebase serve --only functions",
    "shell": "npm run build && firebase functions:shell",
    "start": "npm run shell",
    "deploy": "firebase deploy --only functions",
    "logs": "firebase functions:log"
  },
  "main": "lib/index.js",
  "dependencies": {
    "angular-universal-express-firebase": "0.0.4",
    "firebase-admin": "~6.0.0",
    "firebase-functions": "^2.1.0",
    "@angular/animations": "^7.2.4",
    "@angular/cdk": "^7.3.1",
    "@angular/common": "^7.2.4",
    "@angular/compiler": "^7.2.4",
    "@angular/core": "^7.2.4",
    "@angular/forms": "^7.2.4",
    "@angular/http": "^7.2.4",
    "@angular/material": "^7.3.1",
    "@angular/platform-browser": "^7.2.4",
    "@angular/platform-browser-dynamic": "^7.2.4",
    "@angular/platform-server": "^7.2.4",
    "@angular/router": "^7.2.4",
    "@nguniversal/module-map-ngfactory-loader": "^7.1.0",
    "@ngx-translate/core": "^10.0.2",
    "@ngx-translate/http-loader": "^3.0.1",
    "@types/googlemaps": "^3.30.16",
    "animate.css": "^3.7.0",
    "bootstrap": "^4.2.1",
    "compass": "^0.1.1",
    "compass-sass-mixins": "^0.12.7",
    "contentful": "^6.1.3",
    "core-js": "^2.6.4",
    "emailjs-com": "^2.3.2",
    "flag-icon-css": "^3.2.1",
    "hammerjs": "^2.0.8",
    "jquery": "^3.3.1",
    "marked": "^0.4.0",
    "ngx-bootstrap": "^3.2.0",
    "popper.js": "^1.14.7",
    "rxjs": "^6.4.0",
    "ts-loader": "^5.3.3",
    "web-animations-js": "^2.3.1",
    "webpack-cli": "^3.2.3",
    "zone.js": "^0.8.29",
    "@angular/material-moment-adapter": "7.0.0",
    "@nguniversal/express-engine": "^7.0.0",
    "express": "^4.16.2",
    "moment": "^2.22.2",
    "rxjs-compat": "^6.0.0-rc.0"
  },
  "devDependencies": {
    "typescript": "^3.2.2",
    "@angular-devkit/build-angular": "^0.6.8",
    "@angular/cli": "~7.3.1",
    "@angular/compiler-cli": "^7.2.4",
    "@angular/language-service": "^7.2.4",
    "@types/jasmine": "^2.8.16",
    "@types/jasminewd2": "^2.0.6",
    "@types/node": "~8.9.4",
    "codelyzer": "~4.2.1",
    "jasmine-core": "~2.99.1",
    "jasmine-spec-reporter": "~4.2.1",
    "karma": "~1.7.1",
    "karma-chrome-launcher": "~2.2.0",
    "karma-coverage-istanbul-reporter": "^1.4.3",
    "karma-jasmine": "~1.1.1",
    "karma-jasmine-html-reporter": "^0.2.2",
    "protractor": "^5.4.2",
    "ts-node": "~5.0.1",
    "tslint": "~5.9.1",
    "@types/express": "^4.0.39",
    "http-server": "^0.11.1",
    "karma-cli": "~1.0.1",
    "npm-run-all": "^4.1.2"
  },
  "private": true
}

А это мой index.ts:

import * as angularUniversal from 'angular-universal-express-firebase';


export let ssrApp = angularUniversal.trigger({
  index: __dirname + '/index-server.html',
  main: __dirname + '/main',
  enableProdMode: true,
  cdnCacheExpiry: 600,
  browserCacheExpiry: 300,
  staleWhileRevalidate: 120
});

ng - версия:

Angular CLI: 7.3.1
Node: 10.0.0
OS: win32 x64
Angular: 7.2.4
... animations, common, compiler, compiler-cli, core, forms
... http, language-service, platform-browser
... platform-browser-dynamic, platform-server, router

Package                            Version
------------------------------------------------------------
@angular-devkit/architect          0.6.8
@angular-devkit/build-angular      0.6.8
@angular-devkit/build-optimizer    0.6.8
@angular-devkit/core               0.6.8
@angular-devkit/schematics         7.3.1
@angular/cdk                       7.3.1
@angular/cli                       7.3.1
@angular/material                  7.3.1
@angular/material-moment-adapter   7.0.0
@ngtools/webpack                   6.0.8
@schematics/angular                7.3.1
@schematics/update                 0.13.1
rxjs                               6.4.0
typescript                         3.2.4
webpack                            4.8.3

1 Ответ

0 голосов
/ 26 февраля 2019

ОБНОВЛЕННЫЙ ОТВЕТ:

Проблема, как представляется, заключается в том, что angular-universal-express-firebase использует .mergeMap() для наблюдаемого типа, но с rxjs версия 6 или выше .pipe() необходимо использоватьи .mergeMap() должен быть импортирован из rxjs/operators.

Лучшее решение - это запустить экспресс-приложение самостоятельно в вашем index.ts и развернуть его в облачной функции firebase (что, в сущности, angular-universal-express-firebaseделается).Это дает вам гораздо больший контроль над тем, что выполняется на сервере.

Это мой index.ts:

import * as functions from 'firebase-functions';
import 'zone.js/dist/zone-node';
import 'reflect-metadata';
import {renderModuleFactory} from '@angular/platform-server';
import {provideModuleMap} from '@nguniversal/module-map-ngfactory-loader';
import * as express from 'express';
import {readFileSync} from 'fs';
import {enableProdMode} from '@angular/core';

const {AppServerModuleNgFactory, LAZY_MODULE_MAP} = require('./main');

enableProdMode();

const app = express();

const indexHtml = readFileSync(__dirname + '/index-server.html', 'utf-8').toString();

app.get('*.*', express.static(__dirname + '/dist', {
  maxAge: '1y'
}));

app.route('*').get((req, res) => {

  console.log(req.url);

  renderModuleFactory(AppServerModuleNgFactory, {
    document: indexHtml,
    url: req.url,
    extraProviders: [
      provideModuleMap(LAZY_MODULE_MAP)
    ]
  }).then(html => {
    res.status(200).send(html);
  }).catch(err => {
    console.log(err);
    res.sendStatus(500);
  });

});

exports.ssrApp = functions.https.onRequest(app);

Убедитесь, что вы установили все необходимые пакеты, импортированные сверху.Также в вашем firebase.json убедитесь, что все запросы передаются в облачную функцию:

"rewrites": [
      {
        "source": "**",
        "function": "ssrApp"
      }
    ]

НАЧАЛЬНЫЙ ОТВЕТ:

Кажется, проблема в том, что angular-universal-express-firebase использует .mergeMap() для типа наблюдаемого, но с rxjs версией 6 или выше .pipe() должен быть использован и .mergeMap() должен быть импортирован из rxjs/operators.

После нескольких дней исследований и проб разныхМетоды, это решение, которое работало для меня:

Вместо использования пакета angular-universal-express-firebase я использовал angular7-universal-express-firebase, который в основном обновляет код для обслуживания метода .pipe().

Убедитесь, что вы удалили пакеты angular-universal-express-firebase и angular-universal-express и выполнили следующие команды в папке функций вашего проекта:

npm install angular7-universal-express-firebase

npm install angular7-universal-express

Надеюсь, что это поможет любому, кто столкнется с этой проблемой!

...