Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: update universal guide based on PR 17573 #18707

Closed
wants to merge 3 commits into from

Conversation

wardbell
Copy link
Contributor

@wardbell wardbell commented Aug 15, 2017

Incorporates all changes from PR #17573; please refer to that PR for earlier history.
Cherry picks to side-step merge commits and conflicts

@wardbell wardbell self-assigned this Aug 15, 2017
@wardbell wardbell changed the title docs: update universal guide based on PR 17573 [WIP] docs: update universal guide based on PR 17573 Aug 15, 2017
@mary-poppins
Copy link

You can preview 719a225 at https://pr18707-719a225.ngbuilds.io/.

@mary-poppins
Copy link

You can preview b6f47cd at https://pr18707-b6f47cd.ngbuilds.io/.

@wardbell wardbell added target: major This PR is targeted for the next major release area: core Issues related to the framework runtime labels Aug 15, 2017
@wardbell wardbell added this to WIP in docs Aug 15, 2017
@mary-poppins
Copy link

You can preview 4f5e768 at https://pr18707-4f5e768.ngbuilds.io/.

@mary-poppins
Copy link

You can preview 6ed6562 at https://pr18707-6ed6562.ngbuilds.io/.

@mary-poppins
Copy link

You can preview 6ee9475 at https://pr18707-6ee9475.ngbuilds.io/.

@wardbell wardbell force-pushed the docs-universal branch 2 times, most recently from 28918f9 to e589de4 Compare August 16, 2017 07:42
@mary-poppins
Copy link

You can preview 28918f9 at https://pr18707-28918f9.ngbuilds.io/.

@mary-poppins
Copy link

You can preview e589de4 at https://pr18707-e589de4.ngbuilds.io/.

@mary-poppins
Copy link

You can preview bb2f1c2 at https://pr18707-bb2f1c2.ngbuilds.io/.

@mary-poppins
Copy link

You can preview 0ffed23 at https://pr18707-0ffed23.ngbuilds.io/.

@wardbell wardbell force-pushed the docs-universal branch 2 times, most recently from b8fb21f to ab75906 Compare August 18, 2017 09:09
@mary-poppins
Copy link

You can preview b8fb21f at https://pr18707-b8fb21f.ngbuilds.io/.

@mary-poppins
Copy link

You can preview ab75906 at https://pr18707-ab75906.ngbuilds.io/.

@mary-poppins
Copy link

You can preview 6e38df2 at https://pr18707-6e38df2.ngbuilds.io/.

- based on original effort in PR 17573
Revises both universal and client build to use AOT and webpack for both.
Guide text adjusted accordingly
Dodges CLI client build, expected in near future.
@mary-poppins
Copy link

You can preview 346c676 at https://pr18707-346c676.ngbuilds.io/.

@mary-poppins
Copy link

You can preview 4847bc3 at https://pr18707-4847bc3.ngbuilds.io/.

@wardbell wardbell added action: merge The PR is ready for merge by the caretaker and removed action: cleanup The PR is in need of cleanup, either due to needing a rebase or in response to comments from reviews state: WIP labels Oct 6, 2017
Copy link
Member

@CaerusKaru CaerusKaru left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's a big mistake to not include out-of-the-box support for Angular CLI and ngExpressEngine. Not including these widely-used tools may lead to user confusion and bad practice out of the gate. Many of the guides use these tools and they make for a clearer process. I don't think it would require a lot of refactoring to get this guide in line with those tools, and I would volunteer to do the work myself if it's too much, @wardbell.

I understand the desire to get this guide out ASAP, but I think it's best to hold off, since there are other guides out there in the interim, if it means getting the best guide possible.

All in all though, excellent work putting this together @wardbell, and I don't mean to be harsh.


// #docregion navigation-request
// simplistic regex matches any path without a '.'
const pathWithNoExt = /^([^.]*)$/;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unnecessary, you can just have an app.use('*.*', express.static('dist')); for the static files, and then

app.get('*', (req, res) => {
    res.render('index-universal.html', { req });
}


These web crawlers may be unable to navigate and index your highly-interactive, Angular application as a human user could do.

Angular Universal can generate a static version of your app that is easy searchable, linkable, and navigable without JavaScript.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/s/easy/easily


You must make a few changes to your application code to support both server-side rendering and the transition to the client app.

#### The root `AppModule`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should add a comment on preventing screen "flicker" by adding initialNavigation: 'enabled' to a user's root RouterModule


This guide's sample is written for [Node Express](https://expressjs.com/)
so the engine takes the form of [Express template engine middleware](https://expressjs.com/en/guide/using-template-engines.html).

Copy link
Member

@CaerusKaru CaerusKaru Oct 7, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

authentication and unauthorized access to the rendered pages.

The renderModuleFactory doesn't handle this either. It's a function of the client app to handle this browser-side, i.e. with route guards, and for the /api handle to implement authentication/authorization for those guards with a token/cookie

differentiating static file requests from navigation requests

This is also not handled by the renderModuleFactory directly, it's a function of where you specify server.get('*.*', express.static('dist')), i.e. before the rendering process

where the client sends requests for data.

This is also not handled by the renderModuleFactory, it's a function of where you specify server.get('api/*', ...), i.e. before the rendering process

Do we really want the server to (optionally) compile the module on the server? Shouldn't it be precompiled in the build process as the current guide recommends?

Using the CLI, the module is precompiled, and then used by the ngExpressEngine. You can also pass in the compiled module from your build process. They are equivalent. If you mean precompiling the routes, the universal-starter has a route prerendering element, linked below

It is not clear from the README how you would use this server. It doesn't look like a "normal" express server as most express developers understand "normal". The repo lacks an example.
I can't see the point of recommending two express servers.

ngExpressEngine is not a server, it is a rendering engine for use with server.engine('html', ...). In this way, it is almost entirely comparable with your method, except it is far cleaner

It's not like the ngExpressEngine is self-explanatory

This is a great reason to clarify its use in this guide

Finally, it takes a different approach than the guide and we'd have to alter the proposed guide considerably to accommodate it

Again, since it is mostly comparable to renderModuleFactory, except clearer, it shouldn't be considerably difficult to add the changes

The repo lacks an example

The universal-starter that @Toxicable mentioned has a fantastic example of incorporating the ngExpressEngine, found here

In fact, if the app were _only_ rendered by the server, _every_ app link clicked would arrive at the server
as a navigation URL intended for the router.

Fortunately, application routes have something in common: their URLs lack file extensions.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See nit about this in the server file. Should use express.static instead of creating unnecessary filters and checks

A single `server.use()` treats all other URLs as requests for static assets
such as JavaScript, image, and style files.

To ensure that clients can only download the files that they are _permitted_ to see, you will [put all client-facing asset files in the `/dist` folder](#universal-webpack-configuration)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See nit above about using express.static

constructor(
private http: HttpClient,
@Optional() @Inject(APP_BASE_HREF) origin: string) {
this.searchUrl = (origin || '') + this.searchUrl;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe change to this.searchUrl = `${origin}${this.searchUrl}` to be in line stylistically with other examples, and the very definition of origin in getOrigin?

constructor(
private http: HttpClient,
@Optional() @Inject(APP_BASE_HREF) origin: string) {
this.heroesUrl = (origin || '') + this.heroesUrl;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same nit here as above

import 'rxjs/add/operator/toPromise';
// #enddocregion rxjs
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an RxJS anti-pattern. Please use .call on each operator, or wait until Angular supports RxJS 5.5.0 and its lettable operators

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Explain? I am interested.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

@wardbell wardbell Oct 10, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@CaerusKaru This is an anti-pattern in a library because you risk screwing the consumer of your library, someone you do not and cannot know.

Patching the prototype is OK in your own application. You're not screwing anyone but yourself. The call syntax is bloody awful. It completely destroys the dev experience. Save it for libraries.

The library/app difference is a critically important distinction!

I do hope we all move to lettable when it releases. But it is still in beta as I write this.

Copy link

@Toxicable Toxicable Oct 10, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sadly there's a side effect of even using the lettable method of rxjs right now, it's that if you use that method along side the prototype patching method then you'll end up with duplicated operators in your bundle.
From memory Webpack will solve this in v4 but for now it kinda of stops any libs from using it.
Sorry I don't have a link for this, just recalling it from some issues I've read

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with the reasoning for libraries, but it's also a benefit for tree-shaking. By patching when you need it, you avoid patching everywhere.

I also agree that the call syntax is terrible, I wanted to leave this note here primarily for when lettable operators are usable in Angular core.

npm install webpack @ngtools/webpack copy-webpack-plugin raw-loader @types/express --save-dev
</code-example>

{@a transition}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a section on capturing user processes using @angular/preboot? This should probably be a side note, because getting preboot to work with the current example would require significant refactoring

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was asked to remove the reference to preboot that I had in an early version of this guide.

@chuckjaz chuckjaz added this to the Merge-queue milestone Oct 9, 2017
chuckjaz pushed a commit to chuckjaz/angular that referenced this pull request Oct 9, 2017
- based on original effort in PR 17573

PR Close angular#18707
chuckjaz pushed a commit to chuckjaz/angular that referenced this pull request Oct 9, 2017
Revises both universal and client build to use AOT and webpack for both.
Guide text adjusted accordingly
Dodges CLI client build, expected in near future.

PR Close angular#18707
chuckjaz pushed a commit to chuckjaz/angular that referenced this pull request Oct 9, 2017
@chuckjaz chuckjaz closed this in 0b0d25f Oct 9, 2017
chuckjaz pushed a commit that referenced this pull request Oct 9, 2017
Revises both universal and client build to use AOT and webpack for both.
Guide text adjusted accordingly
Dodges CLI client build, expected in near future.

PR Close #18707
@wardbell wardbell deleted the docs-universal branch October 10, 2017 06:42
@wardbell
Copy link
Contributor Author

wardbell commented Oct 10, 2017

@CaerusKaru We discussed timing internally and decided to forge ahead and revisit as quickly as alternatives allow. It's a judgment call and not mine to make.

I'll look at your other comments when I break free. Thanks very much for making the effort to comment!

When a browser makes an HTTP request, the server can make assumptions about cookies, XSRF headers, etc.

For example, the browser automatically sends auth cookies for the current user.
Angular Universal cannot forward these credentials to a separate data server.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm parroting what I believe I was told by @alxhub

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may be that I'm using ngExpressEngine, which injects the req and res objects from Express by default. Regardless, it's definitely possible to add this functionality in only a couple of lines of code.

Here's the snippet from ngExpressEngine:
https://github.com/angular/universal/blob/2a1246326d5db10a989f143205c2d2ed27f8e362/modules/express-engine/src/main.ts#L129-L143

@chuckjaz
Copy link
Contributor

@wardbell This PR does not apply cleanly on 4.4.x. Can you create a 4.4.x PR with these changes?

@wardbell
Copy link
Contributor Author

@chuckjaz I believe @vikerman is dealing with the 4.4 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 Sep 12, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
action: merge The PR is ready for merge by the caretaker area: core Issues related to the framework runtime cla: yes target: patch This PR is targeted for the next patch release
Projects
No open projects
docs
  
WIP
Development

Successfully merging this pull request may close these issues.

None yet