首页 > 解决方案 > Angular 通用/服务器端渲染丢失文件

问题描述

我正在尝试将我的 Angular 应用程序制作为 ssr,在官方文档中它说我应该运行

webpack --config webpack.server.config.js --progress --colors

但我无法正确编译:

ERROR in ./server.ts
Module not found: Error: Can't resolve './server/main' in '/home/lucaswxp/reduza/reduza-angular'
 @ ./server.ts 18:9-33

有问题的行:

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

这些文件应该是动态创建的,这就是为什么它们需要“require”,但是在 dist 文件夹中的任何地方都没有“server/main.js”文件,这是我在 dist 文件夹中得到的:

out-tsc/
   e2e/
   src/
   node_modules/
reduza-ui/ <-- my project name
   main.08ht283hg20s3.js
server.js
server.js.map

还有我的 angular.json 配置:

"server": {
          "builder": "@angular-devkit/build-angular:server",
          "options": {
            "outputPath": "dist/reduza-ui",
            "main": "src/server.main.ts",
            "tsConfig": "src/server.tsconfig.app.json"
          },
          "configurations": {
            "stable": {
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "namedChunks": false,
              "extractLicenses": true,
              "vendorChunk": false,
              "fileReplacements": [
                { 
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ]
            }
          }
        }

没有“服务器”文件夹。我想不出我错过了什么?我尝试手动包含该文件dist/reduza-ui/main.08ht283hg20s3.js,该文件已编译,但访问时出现以下错误localhost:4000

TypeError: Cannot read property 'moduleType' of undefined
    at /home/lucaswxp/reduza/reduza-angular/dist/server.js:151:1457
    at e.invoke (/home/lucaswxp/reduza/reduza-angular/dist/server.js:1809:7001)
    at Object.onInvoke (/home/lucaswxp/reduza/reduza-angular/dist/server.js:137:1986)
    at e.invoke (/home/lucaswxp/reduza/reduza-angular/dist/server.js:1809:6941)
    at t.run (/home/lucaswxp/reduza/reduza-angular/dist/server.js:1809:2171)
    at e.run (/home/lucaswxp/reduza/reduza-angular/dist/server.js:137:2710)
    at e.bootstrapModuleFactory (/home/lucaswxp/reduza/reduza-angular/dist/server.js:151:1388)
    at md (/home/lucaswxp/reduza/reduza-angular/dist/server.js:1673:888)
    at p.engine (/home/lucaswxp/reduza/reduza-angular/dist/server.js:1794:10074)
    at p.render (/home/lucaswxp/reduza/reduza-angular/dist/server.js:1984:1029)

标签: angular-cli

解决方案


这是文档中的错误。

他们的文档代码是

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

然而,这并不正确,或者至少不是很清楚。

第 1 点:您不应该在生产模式下构建。

尽管您在文档中的一行看到他们希望您在 package.json 的脚本部分中包含一行,例如

ng run my-project:server:production

您不应该这样做,原因有两个:首先,他们更改 angular.json 的指令不包括生产版本。其次,生产版本(如果您只是从实际的非服务器应用程序的生产中复制)以在文件名中包含哈希的方式制作,这会导致文件名为main.a220df2.js. 这当然不理想,因为这意味着您必须一直更改 server.ts。

因此,要么禁用散列,要么"outputHashing": "none"干脆不通过调用ng run my-project:server(简单地删除:production)进行生产构建。

第2点:使用正确require

实际的 require() 调用应该指向您构建的main.server.ts,这是您angular.json在 section 下的引用projects:PROJECTNAME:architect:server。文档已将 outputPath 定义为"outputPath": "dist/my-project-server",,这意味着我们有一个文件正在dist/my-project-server/main.js放置(首先处理第 1 点并禁用 outputHashing 或根本不构建生产模式)。正是这个文件需要require在你的server.ts.

因此,在您的情况下,./dist/reduza-ui/main.js一旦您禁用 outputHasing 或停止在生产模式下构建,它就是您应该包含的文件。

const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/reduza-ui/main');

附加提示:在文档的最顶部,您会看到指向整篇文章完整代码的链接:https ://angular.io/generated/zips/universal/universal.zip 。在那里你可以看到真正的代码应该是什么样子。

让它充分发挥作用的最后两个提示:

第一的

文档在 server.ts 中说:

const template = readFileSync(join(DIST_FOLDER, 'browser', 'index.html')).toString();

browser是您的应用程序的实际默认版本,因此您的常规构建。如果你这样做ng build了,你最终会有一个文件夹,dist/那就是你的实际默认应用程序。这个应用程序的意思是browser。在您的情况下,您命名了您的服务器版本reduza-ui,所以您的实际应用程序可能reduza-ui-default在 dist. 在 server.ts 中需要'reduza-ui-default'代替'browser'几个地方。

第二

此时,当您编译服务器、启动它并在浏览器中请求您的第一页时,您将进入控制台:

StaticInjectorError(Platform: core)[InjectionToken Application Initializer -> InjectionToken DocumentToken]:
  Right-hand side of 'instanceof' is not an object

这是因为 webpack 最小化了你的 server.ts。禁用该使用

optimization: {
    minimize: false
},

webpack.server.config.js.


推荐阅读