-
Notifications
You must be signed in to change notification settings - Fork 24.8k
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
Conversation
719a225
to
b6f47cd
Compare
You can preview 719a225 at https://pr18707-719a225.ngbuilds.io/. |
You can preview b6f47cd at https://pr18707-b6f47cd.ngbuilds.io/. |
b6f47cd
to
4f5e768
Compare
You can preview 4f5e768 at https://pr18707-4f5e768.ngbuilds.io/. |
You can preview 6ed6562 at https://pr18707-6ed6562.ngbuilds.io/. |
6ed6562
to
6ee9475
Compare
You can preview 6ee9475 at https://pr18707-6ee9475.ngbuilds.io/. |
28918f9
to
e589de4
Compare
You can preview 28918f9 at https://pr18707-28918f9.ngbuilds.io/. |
You can preview e589de4 at https://pr18707-e589de4.ngbuilds.io/. |
e589de4
to
bb2f1c2
Compare
You can preview bb2f1c2 at https://pr18707-bb2f1c2.ngbuilds.io/. |
You can preview 0ffed23 at https://pr18707-0ffed23.ngbuilds.io/. |
b8fb21f
to
ab75906
Compare
You can preview b8fb21f at https://pr18707-b8fb21f.ngbuilds.io/. |
You can preview ab75906 at https://pr18707-ab75906.ngbuilds.io/. |
ab75906
to
10f8178
Compare
b0df0df
to
6e38df2
Compare
You can preview 6e38df2 at https://pr18707-6e38df2.ngbuilds.io/. |
6e38df2
to
8ecc585
Compare
- 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.
8ecc585
to
346c676
Compare
You can preview 346c676 at https://pr18707-346c676.ngbuilds.io/. |
346c676
to
4847bc3
Compare
You can preview 4847bc3 at https://pr18707-4847bc3.ngbuilds.io/. |
There was a problem hiding this 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 = /^([^.]*)$/; |
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
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` |
There was a problem hiding this comment.
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). | ||
|
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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'; |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Explain? I am interested.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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} |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
- based on original effort in PR 17573 PR Close angular#18707
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
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
@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. |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
@wardbell This PR does not apply cleanly on 4.4.x. Can you create a 4.4.x PR with these changes? |
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
Incorporates all changes from PR #17573; please refer to that PR for earlier history.
Cherry picks to side-step merge commits and conflicts