angularathens / 2nd-workshop-angular-contrib

2nd workshop on how to contribute to Angular
4 stars 1 forks source link

build(docs-infra): introduce prerendering for angular.io app's `index.html` and `404.html` #10

Open gkalpak opened 3 years ago

gkalpak commented 3 years ago

Investigate enhancing the angular.io app's build process with prerendering (via @angular/platform-server/@nguniversal/express-engine) for:

Context regarding 404.html Currently, a 404 page is generated for the angular.io app using a script, aio/scripts/build-404-page.js, which is invoked as part of the build process using the build-404-page npm script. The page is generated based on a hard-coded template, aio/src/404-body.html, which needs to be manually kept in sync with the actual page's style/layout.

NOTE 1: This is only about prerendering those two pages; it is not about introducing server-side rendering.

NOTE 2: This can be split up by a prerendered page.

Related resources:

gmavridakis commented 3 years ago

Shall i try with your help always? :)

gmavridakis commented 3 years ago

Hello,

I am able to run in local the aio project but facing issues when trying to run pre-render.

More specifically based on 'Blogpost on prerendering with Angular Universal' I followed the below steps:

npx -p @angular/cli@next --> OK ng add @nguniversal/express-engine@next --> OK npm run prerender -- FAILS

[error] Error: Configuration 'production' is not set in the workspace. at WorkspaceNodeModulesArchitectHost.getOptionsForTarget (C:\Users\gregm\Angular\contribution-angular\angular\aio\node_modules\@angular-devkit\architect\node\node-modules-architect-host.js:83:27) at core_1.experimental.jobs.createJobHandler.name (C:\Users\gregm\Angular\contribution-angular\angular\aio\node_modules\@angular-devkit\architect\src\architect.js:172:21) at Observable._subscribe (C:\Users\gregm\Angular\contribution-angular\angular\aio\node_modules\@angular-devkit\core\src\experimental\jobs\create-job-handler.js:92:26) at Observable._trySubscribe (C:\Users\gregm\Angular\contribution-angular\angular\aio\node_modules\@angular-devkit\core\node_modules\rxjs\internal\Observable.js:44:25) at Observable.subscribe (C:\Users\gregm\Angular\contribution-angular\angular\aio\node_modules\@angular-devkit\core\node_modules\rxjs\internal\Observable.js:30:22) at Object.innerSubscribe (C:\Users\gregm\Angular\contribution-angular\angular\aio\node_modules\@angular-devkit\core\node_modules\rxjs\internal\innerSubscribe.js:102:23) at SwitchMapSubscriber._innerSub (C:\Users\gregm\Angular\contribution-angular\angular\aio\node_modules\@angular-devkit\core\node_modules\rxjs\internal\operators\switchMap.js:63:51) at SwitchMapSubscriber._next (C:\Users\gregm\Angular\contribution-angular\angular\aio\node_modules\@angular-devkit\core\node_modules\rxjs\internal\operators\switchMap.js:53:14) at SwitchMapSubscriber.Subscriber.next (C:\Users\gregm\Angular\contribution-angular\angular\aio\node_modules\@angular-devkit\core\node_modules\rxjs\internal\Subscriber.js:66:18) at SwitchMapSubscriber.notifyNext (C:\Users\gregm\Angular\contribution-angular\angular\aio\node_modules\@angular-devkit\core\node_modules\rxjs\internal\operators\switchMap.js:85:26)

Seems that the issue might be with the current version of @angular-devkit

By testing the same guide in another test project it run without any issue so I tried to install same version of @angular-devkit.

npm i @angular-devkit/build-angular@0.1002.0 --save
npm i zone.js

No luck.

So there are two questions:

  1. Any suggestion on the error - if ever faced again or how to proceed?
  2. Regarding the 404 page can you please advise on if there is any route for it? I searched for routing module but didn't find any. This will be needed to declare the prerendered route for 404 pages in anguar.json and not quite sure which route to use.
        "prerender": {
          "builder": "@nguniversal/builders:prerender",
          "options": {
            "browserTarget": "static-app:build:production",
            "serverTarget": "static-app:server:production",
            "routes": ["/" , "???? for 404 page"] // <-- Here you should put the routes you want to prender
          },
gkalpak commented 3 years ago

Thx for looking into this, @gmavridakis!

  1. Regarding the error, as the error message says, the problem is that there is no production configuration for the build target. Instead, in angular.io we have the stable, next and archive configurations (which are equivalent to production). Therefore, you have to update the prerender configuration as follows:

     "prerender": {
       ...
       "options": {
    -    "browserTarget": "site:build:production",
    +    "browserTarget": "site:build:stable",
         "serverTarget": "site:server:production",
         ...
  2. Regarding the route for the 404 page, there is none (by definition :grin:). Maybe you could try using a non-existent route (such as /404.html) and see what happens.

gmavridakis commented 3 years ago

Hi @gkalpak ,

It worked hopefully and now I am getting a new error when I am running with "routes": ["/"]: npm run prerender

Prerendering 1 route(s) to C:\Users\gregm\Angular\contribution-angular\angular\aio\dist\site\browser (node:12900) UnhandledPromiseRejectionWarning: ReferenceError: Element is not defined at C:\Users\gregm\Angular\contribution-angular\angular\aio\dist\site\server\main.js:1:2812194 at Module.uj+Y (C:\Users\gregm\Angular\contribution-angular\angular\aio\dist\site\server\main.js:1:2812373) at webpack_require (C:\Users\gregm\Angular\contribution-angular\angular\aio\dist\site\server\main.js:1:317) at Object.0 (C:\Users\gregm\Angular\contribution-angular\angular\aio\dist\site\server\main.js:1:8631) at webpack_require (C:\Users\gregm\Angular\contribution-angular\angular\aio\dist\site\server\main.js:1:317) at /0p4 (C:\Users\gregm\Angular\contribution-angular\angular\aio\dist\site\server\main.js:1:2513) at Object. (C:\Users\gregm\Angular\contribution-angular\angular\aio\dist\site\server\main.js:1:2558) at Module._compile (internal/modules/cjs/loader.js:956:30) at Object.Module._extensions..js (internal/modules/cjs/loader.js:973:10) at Module.load (internal/modules/cjs/loader.js:812:32) (node:12900) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1) (node:12900) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Keep in note that compilation is completed without any issues but in final stage of prerendering it fails (I can confirm also due to the fact that no original file is generated under dist/browser)

With the help of @bampakoa we tried to investigate further where exactly the issue is and reached to this related issue: https://github.com/angular/angular/issues/27732

Any other suggestions? :D

gkalpak commented 3 years ago

Aha! I think this is this known issue with @angular/elements and universal. It has been fixed in angular/angular#37799, which was released with 10.1.6 and 11.0.0-next.6 (see https://github.com/angular/angular/pull/37799#issuecomment-708420259).

However, angular.io is currently v10.1.3, so the fix is not available there. So, you need to wait for something like angular/angular#39441, that updates angular.io to newer versions.

In the meantime, you can try updating just the @angular/elements package to the latest version (i.e. update package.json > dependencies as shown below and run yarn --cwd=aio):

-    "@angular/elements": "10.1.3",
+    "@angular/elements": "10.2.1",

Let me know if that helps.

bampakoa commented 3 years ago

@gmavridakis we will be having another workshop next Thursday 😃 You are more than welcome to attend if you would like to continue working on the issue. We are here to help 👌 Let me know if you want so that I can send you a Zoom link for the event.

gmavridakis commented 3 years ago

Hi @bampakoa ,

As I am still working on the issue I will not attend this workshop. I will update once I have the final findings or some help is needed.

Thanks

gmavridakis commented 3 years ago

Hi @gkalpak,

So I upgraded to the suggested version but still no luck - getting the same error so not sure if this is related to elements after all.

npm i @angular/elements@10.2.1 --save   
yarn --cwd=aio   
npm run prerender

If there is any other suggestion is more than welcome otherwise I will try to find related issues :)

Thanks

gkalpak commented 3 years ago

I see that you used npm for updating (while the AIO projects uses yarn for dependency management). I am not sure if this may have messed things up. If not, then I am out of ideas, but feel free to put your code on a branch on your remote and I can take a look.

gmavridakis commented 3 years ago

@gkalpak here is the commited code..

Tried with yarn to be sure but I face the same error.

yarn add @angular/elements@10.2.1
yarn --cwd=aio
npm run prerender

Thanks

gkalpak commented 3 years ago

Nice! I noticed that your commit is based on an older commit from master. Can you rebase your branch on top of the latest master commit (which uses v11 for angular.io)? (Before doing that make sure you get rid of the @angular/elements update to 10.2.1, since master is using a more recent version.)

If you are still getting the error, ping me here and I'll take a look.

gmavridakis commented 3 years ago

@gkalpak good news since there is progress :)

I rebased based on master branch which has angular 11 version as suggested and applied again current installation. More specifically as you can see below I run again after the rebase:

yarn setup
ng add @nguniversal/express-engine
npm run prerender

Hopefully, in prerender command, there was no error related to promises as before so you were right it was related to version of Angular. Now the error I get is the below:

yarn setup ng add @nguniversal/express-engine npm run prerender0 info it worked if it ends with ok 1 verbose cli [ 1 verbose cli 'C:\Program Files\nodejs\node.exe', 1 verbose cli 'C:\Program Files\nodejs\node_modules\npm\bin\npm-cli.js', 1 verbose cli 'run', 1 verbose cli 'prerender' 1 verbose cli ] 2 info using npm@6.14.8 3 info using node@v12.20.0 4 verbose run-script [ 'prerender' ] 5 info lifecycle angular.io@0.0.0~prerender: angular.io@0.0.0 6 verbose lifecycle angular.io@0.0.0~prerender: unsafe-perm in lifecycle true 7 verbose lifecycle angular.io@0.0.0~prerender: PATH: .... 8 verbose lifecycle angular.io@0.0.0~prerender: CWD: C:\Users\gregm\Documents\angular\aio 9 silly lifecycle angular.io@0.0.0~prerender: Args: [ '/d /s /c', 'ng run site:prerender' ] 10 silly lifecycle angular.io@0.0.0~prerender: Returned: code: 1 signal: null 11 info lifecycle angular.io@0.0.0~prerender: Failed to exec prerender script 12 verbose stack Error: angular.io@0.0.0 prerender: ng run site:prerender 12 verbose stack Exit status 1 12 verbose stack at EventEmitter. (C:\Program Files\nodejs\node_modules\npm\node_modules\npm-lifecycle\index.js:332:16) 12 verbose stack at EventEmitter.emit (events.js:314:20) 12 verbose stack at ChildProcess. (C:\Program Files\nodejs\node_modules\npm\node_modules\npm-lifecycle\lib\spawn.js:55:14) 12 verbose stack at ChildProcess.emit (events.js:314:20) 12 verbose stack at maybeClose (internal/child_process.js:1022:16) 12 verbose stack at Process.ChildProcess._handle.onexit (internal/child_process.js:287:5) 13 verbose pkgid angular.io@0.0.0 14 verbose cwd C:\Users\gregm\Documents\aaa\angular\aio 15 verbose Windows_NT 10.0.18363 16 verbose argv "C:\Program Files\nodejs\node.exe" "C:\Program Files\nodejs\node_modules\npm\bin\npm-cli.js" "run" "prerender" 17 verbose node v12.20.0 18 verbose npm v6.14.8 19 error code ELIFECYCLE 20 error errno 1 21 error angular.io@0.0.0 prerender: ng run site:prerender 21 error Exit status 1 22 error Failed at the angular.io@0.0.0 prerender script. 22 error This is probably not a problem with npm. There is likely additional logging output above. 23 verbose exit [ 1, true ]

Based on it I understand that the error is in command: ng run site:prerender

So the error I am getting when running this command is:

× Prerendering routes to C:\Users\gregm\Documents\angular\aio\dist\site\browser failed. Unable to render C:\Users\gregm\Documents\angular\aio\dist\site\browser\index.html. Error: HTMLElement is not defined

Now I am focused in server.ts file to figure out why it cannot identify index.html!

Last but not least I committed again all my progress here.

Thanks in regards for your time :D

gkalpak commented 3 years ago

Thx for the update, @gmavridakis :+1:

I took a quick look and this seems to be a bug/incompatibility with elements and universal. The error comes from the fact that the abstract NgElement class (which extends HTMLElement) is defined eagerly in create-custom-element.ts. At the time when the file is loaded on the server, the global object is not yet extended with domino's implementations (which includes HTMLElement).

This is essentially a variation of angular/angular#24551.

Could you please open an issue on the angular/angular repo and provide a description of the problem (feel free to also include my description above) and minimal reproduction of the problem? 🙏

For the reproduction, you should create a branch that is on the same commit as the current master branch and add a commit with the changes introduced by runningng add @nguniversal-express-engine`. This is essentially what you have on your pre-render branch, but with all your commits squahsed into one.

(Feel free to ping me if you need any help with the process and I can also add additional context/details on the issue you will create, if needed.)

gkalpak commented 3 years ago

For reference, here is the issue (reported by @juristr, who ran into the same problem): angular/angular#39950