Reputation: 2119
I'm trying to make my angular app to ssr, in the official documentation it says that I should run
webpack --config webpack.server.config.js --progress --colors
But I can't get it to compile correctly:
ERROR in ./server.ts
Module not found: Error: Can't resolve './server/main' in '/home/lucaswxp/reduza/reduza-angular'
@ ./server.ts 18:9-33
Line with problem:
const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./server/main');
These files are supposed to be created dynamically, that's why they are required with "require", but there's no "server/main.js" file in the dist folder anywhere, this is what I got in the dist folder:
out-tsc/
e2e/
src/
node_modules/
reduza-ui/ <-- my project name
main.08ht283hg20s3.js
server.js
server.js.map
And my angular.json config:
"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"
}
]
}
}
}
There's no "server" folder. I can't figure what did I miss?
I tried including manually the file dist/reduza-ui/main.08ht283hg20s3.js
, this compiled, but I got the following error acessing 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)
Upvotes: 1
Views: 3144
Reputation: 8469
This is an error in the documentation.
Their documentation's code is
const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./server/main');
However, this not correct, or at least not very clear.
Although you see at one line in the documentation that they want you to include in the scripts section of your package.json a line like
ng run my-project:server:production
You shouldn't do that, for two reasons: First, their instruction to change the angular.json does not include the production build. Second, the production build (if you just copied from the production of your actual non-server app) is made in a way to include a hash in the filename, which leads to a file named like main.a220df2.js
. This of course is not ideal, as this would mean you have to change your server.ts all the time.
So, either disable hashing "outputHashing": "none"
or simply don't do a production build by calling ng run my-project:server
(simply remove :production
).
require
The actual require() call should point to your built main.server.ts
, which is references in your angular.json
under the section projects:PROJECTNAME:architect:server
. The documentation has defined the outputPath as "outputPath": "dist/my-project-server",
, which means we have a file in dist/my-project-server/main.js
laying around (take care of point 1 first and disable outputHashing or don't build in production mode at all).
Exactly this file needs to be require
d in your server.ts
.
So, in your case, it's the file ./dist/reduza-ui/main.js
you should include, once your have disabled outputHasing or stopped building in production mode.
const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/reduza-ui/main');
An additional tip: At the very top of the documentation, you see a link to the complete code of the whole article: https://angular.io/generated/zips/universal/universal.zip. There you can see what the real code should look like.
The documentation says in server.ts something like:
const template = readFileSync(join(DIST_FOLDER, 'browser', 'index.html')).toString();
The browser
is the actual default version of your app, so your regular build. If you do ng build
you end up having a folder in dist/
that is your actual default app. This app is meant by browser
. In your case you named your server version reduza-ui
, so maybe your actual app is named reduza-ui-default
in dist. In server.ts needs to be 'reduza-ui-default'
instead of 'browser'
on several places.
At this point, when you compiled your server, started it, and requested your first page in your browser, you get in your console:
StaticInjectorError(Platform: core)[InjectionToken Application Initializer -> InjectionToken DocumentToken]:
Right-hand side of 'instanceof' is not an object
This is because webpack minimizes your server.ts. Disable that using
optimization: {
minimize: false
},
in webpack.server.config.js
.
Upvotes: 2