Skip to content
This repository was archived by the owner on Nov 22, 2024. It is now read-only.

Express Engine returns a 'file not found' error with Angular 9 RC 1, Universal Next 6 #1327

Closed
justinappler opened this issue Nov 9, 2019 · 30 comments
Assignees
Labels
need: repro steps We cannot reproduce the issue with the information given

Comments

@justinappler
Copy link

Bug Report

When serving requests using the express engine and a ServerAppModule built with CLI/Core 9 RC1, the express engine callback contains an error that the component template file cannot be found.

What is the expected behavior?

Engine returns HTML

What is the current behavior?

Engine returns the following error:
Error: ENOENT: no such file or directory, open 'auth-to-contribute.component.html'
(where the component file is part of the ServerAppModule).

What modules are related to this issue?

- [ ] aspnetcore-engine
- [ ] common
- [X] express-engine
- [ ] hapi-engine
- [ ] module-map-ngfactory-loader

Minimal reproduction with instructions:

Don't have a minimal repro case unfortunately.

Environment:

@nguniversal versions

  • aspnetcore-engine:
  • common:
  • express-engine:
  • hapi-engine:
  • module-map-ngfactory-loader:
Angular CLI: 9.0.0-rc.1
Node: 12.12.0
OS: darwin x64
Angular: 9.0.0-rc.1
... animations, cli, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... platform-server, router

Package                                    Version
--------------------------------------------------------------------
@angular-devkit/architect                  0.900.0-rc.1
@angular-devkit/build-angular              0.900.0-rc.1
@angular-devkit/build-optimizer            0.900.0-rc.1
@angular-devkit/core                       9.0.0-rc.1
@angular-devkit/schematics                 9.0.0-rc.1
@angular/cdk                               9.0.0-rc.0
@angular/material                          9.0.0-rc.0
@nguniversal/common                        9.0.0-next.6
@nguniversal/express-engine                9.0.0-next.6
@nguniversal/module-map-ngfactory-loader   9.0.0-next.6
@schematics/angular                        8.0.0
@schematics/update                         0.900.0-rc.1
rxjs                                       6.5.3
typescript                                 3.6.4
webpack                                    4.40.2

Is there anything else we should know?

I started following the stacktrace for where this error is triggered, and it seems to be the if block in _preParseTemplate in directive_normalizer.ts (it ultimately fails to fetch the template). Interestingly, this doesn't appear to be a problem for library component templates (Material2 components don't try to fetch the template as its part of the PrenormalizedTemplateMetadata). For the components internal to my app, however, it tries and fails to find them on the filesystem.

@alan-agius4
Copy link
Collaborator

Hi, I tried to reproduce locally and didn't manage. Can you please share a reproduction?

Also, are you update from an Angular 8 application? If that's the case, did you run ng update @nguniversal/express-engine@next?

Thanks.

@alan-agius4 alan-agius4 added need: investigation Requires some digging to determine if action is needed need: repro steps We cannot reproduce the issue with the information given and removed need: investigation Requires some digging to determine if action is needed labels Nov 11, 2019
@justinappler
Copy link
Author

I tried to do a minimal reproduction and didn't encounter the issue. Apparently it's something specific to my configuration. I was, in fact, upgrading from Angular 8 and did the migration, but the migration is extremely optimistic (it assumes that I can use the server.ts generated by the migration, but my server.ts is more complicated than the out of the box one).

I did however incorporate what seem to be the major changes I've noticed so far going from 8 -> 9.

  1. Removal of the ModuleMapLoader
  2. Switching from bootstrapping the engine using the ServerAppModuleNgFactory to using the ServerAppModule directly

With those changes, I still get this error at the location I mentioned in the "Is there anything else we should know?" section.

@vikerman
Copy link
Contributor

vikerman commented Nov 20, 2019

Hi - I think Point no.2 you mentioned is the issue

Switching from bootstrapping the engine using the ServerAppModuleNgFactory to using the ServerAppModule directly

You are ending up with JIT mode which is probably not what you intended. Can you share how you are building the server bundle. We need to make sure the server build is using AOT mode.

@vikerman vikerman reopened this Nov 20, 2019
@justinappler
Copy link
Author

@vikerman Here is my Angular.json https://gist.github.com/justinappler/aa371fcb9f2fcbbfd1aca071d1c6f95e

To clarify, in v9, I should be using the ServerAppModule, correct? Are you saying that modules can be built either in JIT or AOT mode in v9?

@alan-agius4
Copy link
Collaborator

alan-agius4 commented Nov 20, 2019 via email

@alan-agius4
Copy link
Collaborator

I think what is happening is that you are compiling your server app entirely with webpack ts-loader which is ending up being compiled in JIT mode.

In v9, the external webpack-cli part was removed and is now part of ng run project:server.

During v9 update there are also a couple of changes apart from the changes mentioned above.

These are;

  • tsconfig.server.json
  • package.json changes (scripts/dependencies)
  • angular.json changes
  • main.server.ts changes
  • server.ts

I would strongly recommend to use ng update and than update the server.ts with your logic.

Also, are you using Ivy or VE?

@justinappler
Copy link
Author

justinappler commented Nov 20, 2019

@alan-agius4 So I'm actually building the server bundle with the CLI using the @angular-devkit/build-angular:server builder and the CLI, then building an Express server server.ts bundle using a custom webpack config (and require()ing the Angular server module bundle that was generated by the server builder into the express server.ts bundle). The custom webpack TS Loader for the express server does not compile any part of the Angular code.

It's not trivial for us to just move all the express server code we wrote over to the server.ts that is generated as part of the 9.0 migration. If that's what we need to do, our migration path just got a lot longer. What I'm trying to do is figure out the differences, and apply those differences to my express server.

I think I'm using Ivy, in that I'm using 9.0 and not turning Ivy off in the tsconfig. It seems possible though, per @vikerman 's comment, that my server bundle is not getting built in AOT mode (hence why it can't find the template files).

@alan-agius4
Copy link
Collaborator

alan-agius4 commented Nov 21, 2019

I have a hunch on what's happening.

Since you are using the CLI to build your server, your build is AOT because in the CLI we don't offer a way to build a server in JIT mode. What I think is happening is that you are fall backing to JIT mode during runtime.

I am going to assume a couple of things and kindly correct me if this is not the case in your project.

  1. You previously didn't bundle server dependencies via the bundleDependencies option
  2. In your server.ts file you have imports to @angular/<package> and/or @nguniversal/<package>

Node is unable to resolve the entrypoints generated by NGCC integration with the CLI. Since such entrypoints are created to be used by bundlers. One example of such entrypoints is the main field in package.json which points to the VE version of the code, while running NGCC via the CLI a new field will be created ex: main_ivy_ngcc points which points to the Ivy version of the code.

To keep your existing setup with a separate webpack compilation with ts-loader for your server.ts file.

You need to do a couple of things:

  • Disable server dependency bundling which can be done via the angular.json configuration. Under your server target options add "bundleDependencies": "none"
  • Run NGCC binary prior to building. This can be done by adding a postinstall script in your package.json - "postinstall": "ngcc"

Nb: After doing the above changes you need to nuke your node_modules and install them again.

rm -rf node_modules
npm/yarn install

With this approach the entrypoints will be overridden with the Ivy equivalent which will cause Node to be able to resolve such entrypoints during runtime.

@justinappler
Copy link
Author

Hi @alan-agius4 ,

I followed the steps you suggested, and did the following:

Modified the server target and set "bundleDependencies": "none". This doesn't appear to have been applied before as the server bundle went from ~20MB to ~7MB.

My package.json already had a postinstall script from the migration to Angular 9 with the following command:

ngcc --properties es2015 browser module main --first-only --create-ivy-entry-points

This command runs fine. However, when I modified it to be simply ngcc, I get the following error and it doesn't finish:

Error: Error on worker #6: Error: Unable to write a reference to CdkCopyToClipboard in /Users/justinappler/crunchbase/client_app/node_modules/@angular/cdk/esm2015/clipboard/copy-to-clipboard.js from /Users/justinappler/crunchbase/client_app/node_modules/@angular/cdk/esm2015/clipboard/clipboard-module.js
    at ReferenceEmitter.emit (/Users/justinappler/crunchbase/client_app/node_modules/@angular/compiler-cli/src/ngtsc/imports/src/emitter.js:55:19)
    at Object.toR3Reference (/Users/justinappler/crunchbase/client_app/node_modules/@angular/compiler-cli/src/ngtsc/annotations/src/util.js:165:31)
    at NgModuleDecoratorHandler._toR3Reference (/Users/justinappler/crunchbase/client_app/node_modules/@angular/compiler-cli/src/ngtsc/annotations/src/ng_module.js:348:31)
    at /Users/justinappler/crunchbase/client_app/node_modules/@angular/compiler-cli/src/ngtsc/annotations/src/ng_module.js:173:83
    at Array.map (<anonymous>)
    at NgModuleDecoratorHandler.analyze (/Users/justinappler/crunchbase/client_app/node_modules/@angular/compiler-cli/src/ngtsc/annotations/src/ng_module.js:173:48)
    at Object.analyzeDecorators (/Users/justinappler/crunchbase/client_app/node_modules/@angular/compiler-cli/ngcc/src/analysis/util.js:75:38)
    at DecorationAnalyzer.analyzeClass (/Users/justinappler/crunchbase/client_app/node_modules/@angular/compiler-cli/ngcc/src/analysis/decoration_analyzer.js:138:40)
    at /Users/justinappler/crunchbase/client_app/node_modules/@angular/compiler-cli/ngcc/src/analysis/decoration_analyzer.js:131:55
    at Array.map (<anonymous>)
    at ClusterMaster.onWorkerMessage (/Users/justinappler/crunchbase/client_app/node_modules/@angular/compiler-cli/ngcc/src/execution/cluster/master.js:158:27)
    at /Users/justinappler/crunchbase/client_app/node_modules/@angular/compiler-cli/ngcc/src/execution/cluster/master.js:46:95
    at ClusterMaster.<anonymous> (/Users/justinappler/crunchbase/client_app/node_modules/@angular/compiler-cli/ngcc/src/execution/cluster/master.js:238:57)
    at step (/Users/justinappler/crunchbase/client_app/node_modules/tslib/tslib.js:136:27)
    at Object.next (/Users/justinappler/crunchbase/client_app/node_modules/tslib/tslib.js:117:57)
    at /Users/justinappler/crunchbase/client_app/node_modules/tslib/tslib.js:110:75
    at new Promise (<anonymous>)
    at Object.__awaiter (/Users/justinappler/crunchbase/client_app/node_modules/tslib/tslib.js:106:16)
    at EventEmitter.<anonymous> (/Users/justinappler/crunchbase/client_app/node_modules/@angular/compiler-cli/ngcc/src/execution/cluster/master.js:232:32)
    at EventEmitter.emit (events.js:210:5)

If I clear node_modules, yarn install, run the original ngcc command with the additional flags, build the server module bundle, build the server.ts bundle, then run it, I still get the 'cant find component file'.

Also, just want to say that I really appreciate your help in debugging this and providing so much direct assistance.

@alan-agius4
Copy link
Collaborator

alan-agius4 commented Nov 21, 2019

The below NGCC binary call will only work if you use the CLI to bundle all your bundles.

ngcc --properties es2015 browser module main --first-only --create-ivy-entry-points

Note: that now we removed this has been removed and no longer gets added in project when they migrate.

The Error on worker #6: Error: Unable to write a reference error you are experiencing should be solved or at least it should happen far less often in RC 3 as per angular/angular@14156bd

@alan-agius4
Copy link
Collaborator

Any luck with RC 3?

@justinappler
Copy link
Author

@alan-agius4 Same error unfortunately. I've started focusing my efforts on trying to move code out of the express server so that I can build it without a customized Webpack config (and thus move it under the purview of the CLI).

@alan-agius4
Copy link
Collaborator

Awesome, if you have any questions or queries let me know 😊

@justinappler
Copy link
Author

@alan-agius4 So I've now done the needed changes to get our app to use the CLI to build the server. The compilation looks like it worked fine (I get a single main.js bundle now that starts the express server properly). That said, the issue persists 😞 (rendering a page errors with an inability to fine a template HTML file).

One thing I've noticed: the CLI seems to be doing a replacement of process.env.NODE_ENV with the string development. It's not great that the CLI does this replacement, but setting that aside, it seems strange that the CLI's webpack is setting that variable to development when running this in the production configuration. What is it in the server devkit builder that handles putting the server bundle build into AOT/Prod mode, because that seems to not be working for me.

@alan-agius4
Copy link
Collaborator

That replacement is done by webpack it reflects the mode that webpack is running.

To enable prod modeyou need to enable the optimization option:

That being said, dev/prod mode shouldn’t cause that error.

@justinappler
Copy link
Author

@alan-agius4 Interestingly, switching to optimization: :"true" changed the error. Now I'm getting a "No NgModule metadata found for 'ServerAppModule'." error.

@alan-agius4
Copy link
Collaborator

Can you kindly send a snippet of the compiled a component/module ideally without optimizations please?

@justinappler
Copy link
Author

@alan-agius4 Here you go: https://drive.google.com/file/d/1VX2Qp6sbsFT6O-I9IAhRj5xJy505HzL7/view?usp=sharing

Also happy to jump on a Hangout/Zoom or something if it helps, just let me know (you can reach out directly at justin (at) crunchbase.com)

@alan-agius4
Copy link
Collaborator

@justinappler, thanks for the above.

Let me go through that and will reach out to you in a day or two.

Thanks once again.

@alan-agius4
Copy link
Collaborator

alan-agius4 commented Nov 26, 2019

Bdw, I couldn't help but notice but auth-to-contribute.component.html is not part of the bundle. How is this being loaded?

@justinappler
Copy link
Author

@alan-agius4 It's definitely in there, I think Google Drive lazy loads the document as you scroll through:
Screen Shot 2019-11-26 at 10 40 32 AM

@alan-agius4
Copy link
Collaborator

Silly me you are right, I'll download it and review it tomorrow. Thanks once again for your copereration.

@alan-agius4 alan-agius4 self-assigned this Nov 26, 2019
@alan-agius4
Copy link
Collaborator

alan-agius4 commented Nov 26, 2019

2 questions;

  1. Does the error appear when using bundleDependencies: all or remove this setting (Which in version 9 is enabled by default), as I noticed that node_modules are external in your bundle?
/***/ "@angular/core":
/*!********************************!*\
  !*** external "@angular/core" ***!
  \********************************/
/*! no static exports found */
/***/ (function(module, exports) {

module.exports = require("@angular/core");

/***/ }),
  1. Since you have node dependencies not bundled you are using the NGCC postinstall hook? If so, make sure you are not passing one of the following. --first-only or --create-ivy-entry-points as otherwise the resolve dependency would be resolved to the VE version. (Note: if you have these settings, you will need to do a fresh npm install after removing them.)

Thanks before hand.

@alan-agius4
Copy link
Collaborator

alan-agius4 commented Nov 26, 2019

Note: if remove bundleDependencies : none, you don't need to alter the ngcc postinstall hook or you might want to consider to remove it altogether.

@justinappler
Copy link
Author

Progress! When I change the postinstall script to: ngcc --properties es2015 browser module main and keep bundleDependencies: "none" and optimization: true, requests no longer return an error. I get a new error that seems to prevent page from actually rendering on the server, but it appears unrelated to this issue:

ERROR Error: Multiple components match node with tagname mat-toolbar
    at throwMultipleComponentError (/node_modules/@angular/core/bundles/core.umd.js:5443:15)
    at findDirectiveMatches (/node_modules/@angular/core/bundles/core.umd.js:9633:29)
    at resolveDirectives (/node_modules/@angular/core/bundles/core.umd.js:9494:26)
    at Object.ɵɵelementStart (/node_modules/@angular/core/bundles/core.umd.js:15949:33)

So, if I'm not bundling dependencies (which I'd prefer not to for build speed and such), it seems I'll need to keep the postinstall script as it is above?

@alan-agius4
Copy link
Collaborator

So, if I'm not bundling dependencies (which I'd prefer not to for build speed and such), it seems I'll need to keep the postinstall script as it is above?

Yes that is correct.

@alan-agius4
Copy link
Collaborator

alan-agius4 commented Nov 26, 2019

Indeed the error you are seeing doesn’t seem to be related to this issue. And now you are running in Ivy mode.

@justinappler
Copy link
Author

So, if I'm not bundling dependencies (which I'd prefer not to for build speed and such), it seems I'll need to keep the postinstall script as it is above?

Yes that is correct.

OK, thats seems very doable.

Indeed the error you are seeing doesn’t seem to be related to this issue. And now you are running in Ivy mode.

Excellent, I'll look into that issue separately. Hopefully after that I can get a sense of the SSR performance with Ivy! Thanks for your help!

@alan-agius4
Copy link
Collaborator

Closing as the original error seems to have been resolved.

Please feel free to open a new issue, if you have any further problems.

@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Dec 31, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
need: repro steps We cannot reproduce the issue with the information given
Projects
None yet
Development

No branches or pull requests

3 participants