SSR Angular 8 应用程序具有未定义的惰性加载模块。

7

我正在尝试使用SSR启动我的Angular 8应用程序,但是当我使用ng serve运行应用程序时,我的懒加载模块会触发webpack中的一些未定义错误。 在Angular 7下之前可以正常工作,但升级到Angular 8后出现问题。 这是我在运行时(在节点控制台中)收到的错误。

ERROR Error: Uncaught (in promise): TypeError: Cannot read property 'call' of undefined
TypeError: Cannot read property 'call' of undefined
    at __webpack_require__ (/Users/gwenaellarmet/Documents/Projects/ng-nouma/dist/server.js:137403:30)
    at Function.requireEnsure [as e] (/Users/gwenaellarmet/Documents/Projects/ng-nouma/dist/server.js:137422:25)
    at ɵ11 (/Users/gwenaellarmet/Documents/Projects/ng-nouma/dist/server.js:139660:6210)
    at RouterConfigLoader.loadModuleFactory (/Users/gwenaellarmet/Documents/Projects/ng-nouma/dist/server.js:232758:39)

我尝试更改了一些tsconfig和angular.json的配置,但是始终遇到相同的错误。 Ivy未启用,因为它在构建时也会触发一些错误;我认为它们有关联,但现在我正在尝试在没有Ivy的情况下使其工作。

ERROR in src/app/pages/search/search.module.ts(68,12): error TS-991010: Value at position 12 in the NgModule.importss of SearchModule is not a reference: [object Object]
src/app/app.module.ts(41,12): error TS-991010: Value at position 6 in the NgModule.importss of AppModule is not a reference: [object Object]

tsconfig.json

{
  "compileOnSave": false,
  "angularCompilerOptions": {
    "enableIvy": true,
    "allowEmptyCodegenFiles": true
  },
  "compilerOptions": {
    "baseUrl": "./src",
    "importHelpers": true,
    "paths": {
      "@nouma/core": ["app/core/core.index.ts"],
      "@nouma/coreModule": ["app/core/core.module.ts"],
      "@nouma/material": ["app/utils/nouma-material/nouma-material.module.ts"],
      "@nouma/ui": ["app/ui/ui.index.ts"],
      "@nouma/env": ["environments/environment.ts"],
      "@nouma/errors": ["app/pages/error-pages/error-pages.index.ts"],
      "@nouma/home": ["app/pages/home/home.component.ts"],
      "@nouma/popins": ["app/pages/popins/popins.index.ts"],
      "@nouma/popinsModule": ["app/pages/popins/popins.module.ts"]
    },
    "incremental": true,
    "outDir": "./dist/out-tsc",
    "sourceMap": true,
    "declaration": false,
    "module": "esnext",
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "target": "es5",
    "typeRoots": [
      "node_modules/@types"
    ],
    "lib": [
      "es2018",
      "dom"
    ]
  }
}

tsconfig.server.json

{
  "extends": "./tsconfig.app.json",
  "compilerOptions": {
    "outDir": "../out-tsc/app-server",
    "baseUrl": "."
  },
  "angularCompilerOptions": {
    "entryModule": "app/app.server.module#AppServerModule"
  }
}

angular.json

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "ng-nouma": {
      "root": "",
      "sourceRoot": "src",
      "projectType": "application",
      "prefix": "app",
      "schematics": {},
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "dist/browser",
            "index": "src/index.html",
            "main": "src/main.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "src/tsconfig.app.json",
            "assets": [
              "src/favicon.ico",
              "src/robots.txt",
              "src/assets"
            ],
            "styles": [
              "src/app/utils/nouma-material/nouma-app-theme.scss",
              "src/styles.scss"
            ],
            "scripts": [
              "node_modules/jquery/dist/jquery.min.js",
              "node_modules/foundation-sites/dist/js/foundation.min.js"
            ],
            "lazyModules": [
              "src/app/pages/search/search.module",
              "src/app/pages/search/search.module",
              "src/app/pages/tender-detail/tender-detail.module",
              "src/app/pages/sources/sources.module",
              "src/app/pages/offer/offer.module",
              "src/app/pages/forgotten/forgotten.module",
              "src/app/pages/confirm/confirm.module",
              "src/app/pages/alerts/alerts.module",
              "src/app/pages/bookmarks/bookmarks.module",
              "src/app/pages/account/account.module",
              "src/app/pages/home/home.module"
            ]
          },
          "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": false,
              "vendorChunk": false,
              "buildOptimizer": true
            },
            "local": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.local.ts"
                }
              ]
            }
          }
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "browserTarget": "ng-nouma:build"
          },
          "configurations": {
            "production": {
              "browserTarget": "ng-nouma:build:production"
            },
            "local": {
              "browserTarget": "ng-nouma:build:local"
            }
          }
        },
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "browserTarget": "ng-nouma: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": [
              "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
              "src/styles.scss"
            ],
            "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": "dist/server",
            "main": "src/main.server.ts",
            "tsConfig": "src/tsconfig.server.json"
          },
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ]
            },
            "local": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.local.ts"
                }
              ]
            }
          }
        }
      }
    },
    "ng-nouma-e2e": {
      "root": "e2e/",
      "projectType": "application",
      "architect": {
        "e2e": {
          "builder": "@angular-devkit/build-angular:protractor",
          "options": {
            "protractorConfig": "e2e/protractor.conf.js",
            "devServerTarget": "ng-nouma:serve"
          },
          "configurations": {
            "production": {
              "devServerTarget": "ng-nouma:serve:production"
            },
            "local": {
              "devServerTarget": "ng-nouma:serve:local"
            }
          }
        },
        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": "e2e/tsconfig.e2e.json",
            "exclude": [
              "**/node_modules/**"
            ]
          }
        }
      }
    }
  },
  "defaultProject": "ng-nouma",
  "schematics": {
    "@schematics/angular:component": {
      "styleext": "scss"
    }
  }
}

packages.json

{
  "name": "ng-nouma",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "postinstall": "ivy-ngcc",
    "start": "ng serve",
    "start:opti": "ng serve --aot --optimization",
    "start:local": "ng serve --configuration=local",
    "start:prod": "ng serve --configuration=production",
    "build": "ng build --aot --build-optimizer --optimization",
    "build:prod": "ng build --prod --aot --build-optimizer --optimization",
    "build:local": "ng build --configuration=local --aot --build-optimizer --optimization",
    "test": "ng test",
    "lint": "ng lint",
    "bundle-report": "ng build --stats-json --aot --build-optimizer --optimization && webpack-bundle-analyzer dist/browser/stats.json",
    "bundle-report:prod": "ng build --stats-json --prod --aot --build-optimizer --optimization && webpack-bundle-analyzer dist/browser/stats.json",
    "e2e": "ng e2e",
    "compile:server": "webpack --config webpack.server.config.js --progress --colors",
    "serve:ssr": "node dist/server",
    "build:ssr": "npm run build:client-and-server-bundles && npm run compile:server",
    "build:ssr:staging": "npm run build:client-and-server-bundles:staging && npm run compile:server",
    "build:ssr:local": "npm run build:client-and-server-bundles:local && npm run compile:server",
    "build:client-and-server-bundles": "ng build --prod --aot --build-optimizer --optimization && ng run ng-nouma:server:production",
    "build:client-and-server-bundles:staging": "ng build --aot --build-optimizer --optimization && ng run ng-nouma:server",
    "build:client-and-server-bundles:local": "ng build --aot --build-optimizer --optimization --configuration=local && ng run ng-nouma:server"
  },
  "private": true,
  "dependencies": {
    "@agm/core": "^1.0.0-beta.5",
    "@angular/animations": "^8.0.0",
    "@angular/cdk": "~8.0.0",
    "@angular/common": "^8.0.0",
    "@angular/compiler": "^8.0.0",
    "@angular/core": "^8.0.0",
    "@angular/forms": "^8.0.0",
    "@angular/material": "^8.0.0",
    "@angular/platform-browser": "^8.0.0",
    "@angular/platform-browser-dynamic": "^8.0.0",
    "@angular/platform-server": "^8.0.0",
    "@angular/router": "^8.0.0",
    "@fortawesome/angular-fontawesome": "^0.4.0",
    "@fortawesome/fontawesome-pro": "^5.8.2",
    "@fortawesome/fontawesome-svg-core": "^1.2.18",
    "@fortawesome/free-brands-svg-icons": "^5.8.2",
    "@fortawesome/pro-light-svg-icons": "^5.8.2",
    "@fortawesome/pro-regular-svg-icons": "^5.8.2",
    "@fortawesome/pro-solid-svg-icons": "^5.8.2",
    "@nguniversal/common": "^7.1.1",
    "@nguniversal/express-engine": "^7.1.1",
    "@nguniversal/module-map-ngfactory-loader": "^7.1.1",
    "angular2-toaster": "^7.0.0",
    "angulartics2": "^7.5.2",
    "core-js": "^3.1.3",
    "express": "^4.17.1",
    "foundation-sites": "6.5.3",
    "hammerjs": "^2.0.8",
    "jquery": "^3.4.1",
    "ng-intercom": "^8.0.0-beta.1",
    "ngx-chips": "^2.0.0-beta.0",
    "ngx-cookie-service": "^2.2.0",
    "ngx-foundation": "1.0.8",
    "ngx-infinite-scroll": "^7.1.0",
    "ngx-mask": "^7.9.9",
    "rxjs": "~6.5.2",
    "sass-loader": "^7.1.0",
    "terser": "^4.0.0",
    "tslib": "^1.9.0",
    "zone.js": "~0.9.1"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "~0.800.0",
    "@angular/cli": "~8.0.0",
    "@angular/compiler-cli": "^8.0.0",
    "@angular/language-service": "^8.0.0",
    "@types/jasmine": "~3.3.13",
    "@types/jasminewd2": "~2.0.3",
    "@types/node": "~12.0.3",
    "codelyzer": "^5.0.1",
    "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.5",
    "karma-jasmine": "~2.0.1",
    "karma-jasmine-html-reporter": "^1.4.2",
    "protractor": "~5.4.0",
    "ts-loader": "^6.0.1",
    "ts-node": "~8.2.0",
    "tslint": "~5.16.0",
    "typescript": "~3.4.5",
    "webpack-bundle-analyzer": "^3.3.2",
    "webpack-cli": "^3.2.0"
  }
}

我使用npm run build:ssr构建应用程序,并使用npm run serve:ssr提供服务。
出于SEO的目的,我需要我的应用程序使用SSR渲染所有模块和标记,并希望得到一些帮助以确定问题所在。

你是否已经将所有的Angular 8 loadChildren路由迁移? - Reactgular
好主意,我要试试看。 - Gwenael Larmet
这个错误在 server.js 文件中。如果我没记错的话,这个文件不是 Angular 捆绑包的一部分。它们是单独加载的。所以我想知道服务器是否在开始时无法引导应用程序模块。我会尝试在调试器中运行 SSR。 - Reactgular
没有任何懒加载模块,一切都正常工作,所以问题就在这里,正如我所预料的那样,我将尝试调试SSR以找到问题的确切位置。 - Gwenael Larmet
"Ivy不会准备好所有用例。例如i18n或Angular Universal等某些功能在预览版中可能仍然没有完全兼容性。" - Gilsdav
显示剩余2条评论
3个回答

16
问题在于旧的设置方式中存在两份Angular,这会混淆懒加载系统。
您可以通过更新以下内容来手动解决此问题: package.json
添加“--bundleDependencies all”到“build:client-and-server-bundles”的值的末尾。
server.ts
删除以下行。
import {enableProdMode} from '@angular/core';     
import {ngExpressEngine} from '@nguniversal/express-engine';  
import {provideModuleMap} from '@nguniversal/module-map-ngfactory-loader';
enableProdMode();
const {AppServerModuleNgFactory, LAZY_MODULE_MAP} = require('./dist/server/main');

然后添加

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

webpack.server.config.js

添加

externals: {
 './dist/server/main': 'require("./server/main")'
}
参考文献:修复懒加载和bundleDependencies。(链接)

1
这个回复解决了我的问题,确实是这个问题,Universal团队正在为Angular 8发布而努力。我不明白为什么这个回复会被踩。非常感谢@paulws。 - Gwenael Larmet
1
在最终构建后,我遇到了以下错误:“错误:找不到模块' require("./server/main")'”。 - Abijith Ajayan
这个答案对我有用,除了最后一部分。我不得不删除externals: { './dist/server/main': 'require("./server/main")' }谢谢 - user1122002
1
现在@nguniversal/module-map-ngfactory-loader已被弃用。 - azerafati

0

-1
长话短说 - 我刚从 server.ts 中删除了 enableProdMode();,现在它可以正常工作了。

这是由Angular 7创建的,但是在Angular 8中需要更改server.ts文件的代码,因此

  • 我创建了server.bak.ts作为备份文件,
  • 使用SSR设置了新的空项目,并且
  • 从中获取了代码到server.ts文件中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接