angular-cli - 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)
解决方案
这是文档中的错误。
他们的文档代码是
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
.
推荐阅读
- python - 使用多处理、生成器函数和抓取网址时遇到问题
- laravel - Laravel 6关系输出为数组而不是对象
- c# - OData 返回'找不到路由'odata-Unversioned'的服务容器
- flutter - 在没有 Web 服务器的情况下运行 Flutter for Web
- c# - 如何在 wix 工具集中获取 BrowseDlg?
- rxjs - 可观察管道
- groovy - 如何从数组中删除空元素
- c++ - 使用 CMake 和 Visual Studio 2019 编译 GLEW?
- python - 如何使用 pandas 将 API 中的数据拆分为行和列?
- angular - 拖放自定义行为