You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/documentation/stories/universal-rendering.md
+221-39
Original file line number
Diff line number
Diff line change
@@ -1,23 +1,32 @@
1
-
# Universal bundles
1
+
# Angular Universal Integration
2
2
3
-
Angular CLI supports generation of a Universal build for your application. This is a CommonJS-formatted bundle which can be `require()`'d into a Node application (for example, an Express server) and used with `@angular/platform-server`'s APIs to prerender your application.
3
+
The Angular CLI supports generation of a Universal build for your application. This is a CommonJS-formatted bundle which can be `require()`'d into a Node application (for example, an Express server) and used with `@angular/platform-server`'s APIs to prerender your application.
4
4
5
-
This story will show you how to set up Universal bundling for an existing `@angular/cli` project in 4 steps.
5
+
---
6
6
7
-
## Step 0: Install `@angular/platform-server`
7
+
## Example CLI Integration:
8
+
9
+
[Angular Universal-Starter](https://github.com/angular/universal-starter/tree/master/cli) - Clone the universal-starter, and check out the `/cli` folder for a working example.
10
+
11
+
---
12
+
13
+
# Integrating Angular Universal into existing CLI Applications
14
+
15
+
This story will show you how to set up Universal bundling for an existing `@angular/cli` project in 5 steps.
16
+
17
+
---
18
+
19
+
## Install Dependencies
8
20
9
21
Install `@angular/platform-server` into your project. Make sure you use the same version as the other `@angular` packages in your project.
10
22
23
+
> You'll also need @nguniversal/module-map-ngfactory-loader, as it's used to handle lazy-loading in the context of a server-render. (by loading the chunks right away)
## Step 1: Prepare your app for Universal rendering
29
+
## Step 1: Prepare your App for Universal rendering
21
30
22
31
The first thing you need to do is make your `AppModule` compatible with Universal by addding `.withServerTransition()` and an application ID to your `BrowserModule` import:
23
32
@@ -46,7 +55,7 @@ This example places it alongside `app.module.ts` in a file named `app.server.mod
@@ -67,14 +76,15 @@ import {AppComponent} from './app.component';
67
76
exportclassAppServerModule {}
68
77
```
69
78
70
-
## Step 2: Create a server main file and tsconfig to build it
79
+
---
80
+
## Step 2: Create a server "main" file and tsconfig to build it
71
81
72
82
Create a main file for your Universal bundle. This file only needs to export your `AppServerModule`. It can go in `src`. This example calls this file `main.server.ts`:
Copy `tsconfig.app.json` to `tsconfig.server.json` and change it to build with a `"module"` target of `"commonjs"`.
@@ -105,6 +115,7 @@ Add a section for `"angularCompilerOptions"` and set `"entryModule"` to your `Ap
105
115
}
106
116
```
107
117
118
+
---
108
119
## Step 3: Create a new project in `.angular-cli.json`
109
120
110
121
In `.angular-cli.json` there is an array under the key `"apps"`. Copy the configuration for your client application there, and paste it as a new entry in the array, with an additional key `"platform"` set to `"server"`.
@@ -118,16 +129,17 @@ Then, remove the `"polyfills"` key - those aren't needed on the server, and adju
118
129
...
119
130
"apps": [
120
131
{
121
-
// Keep your original application config intact here.
122
-
// It will be app 0.
132
+
// Keep your original application config intact here, this is app 0
133
+
// -EXCEPT- for outDir, udpate it to dist/browser
134
+
"outDir":"dist/browser"// <-- update this
123
135
},
124
136
{
125
137
// This is your server app. It is app 1.
126
138
"platform":"server",
127
139
"root":"src",
128
-
// Build to dist-server instead of dist. This prevents
140
+
// Build to dist/server instead of dist. This prevents
129
141
// client and server builds from overwriting each other.
130
-
"outDir":"dist-server",
142
+
"outDir":"dist/server",
131
143
"assets": [
132
144
"assets",
133
145
"favicon.ico"
@@ -163,41 +175,211 @@ Then, remove the `"polyfills"` key - those aren't needed on the server, and adju
163
175
With these steps complete, you should be able to build a server bundle for your application, using the `--app` flag to tell the CLI to build the server bundle, referencing its index of `1` in the `"apps"` array in `.angular-cli.json`:
164
176
165
177
```bash
166
-
# This builds the client application in dist/
178
+
# This builds the client application in dist/browser/
With this bundle built, you can use `renderModuleFactory` from `@angular/platform-server` to test it out.
181
194
182
-
```javascript
183
-
// Load zone.js for the server.
184
-
require('zone.js/dist/zone-node');
195
+
## Step 4: Setting up an Express Server to run our Universal bundles
196
+
197
+
Now that we have everything set up to -make- the bundles, how we get everything running?
198
+
199
+
PlatformServer offers a method called `renderModuleFactory()` that we can use to pass in our AoT'd AppServerModule, to serialize our application, and then we'll be returning that result to the Browser.
200
+
201
+
```typescript
202
+
app.engine('html', (_, options, callback) => {
203
+
renderModuleFactory(AppServerModuleNgFactory, {
204
+
// Our index.html
205
+
document: template,
206
+
url: options.req.url,
207
+
// DI so that we can get lazy-loading to work differently (since we need it to just instantly render it)
208
+
extraProviders: [
209
+
provideModuleMap(LAZY_MODULE_MAP)
210
+
]
211
+
}).then(html=> {
212
+
callback(null, html);
213
+
});
214
+
});
215
+
```
216
+
217
+
You could do this, if you want complete flexibility, or use an express-engine with a few other built in features from [`@nguniversal/express-engine`](https://github.com/angular/universal/tree/master/modules/express-engine) found here.
Below we can see a TypeScript implementation of a -very- simple Express server to fire everything up.
232
+
233
+
> Note: This is a very bare bones Express application, and is just for demonstrations sake. In a real production environment, you'd want to make sure you have other authentication and security things setup here as well. This is just meant just to show the specific things needed that are relevant to Universal itself. The rest is up to you!
234
+
235
+
At the ROOT level of your project (where package.json / etc are), created a file named: **`server.ts`**
236
+
237
+
### ./server.ts (root project level)
238
+
239
+
```typescript
240
+
// These are important and needed before anything else
In the future when you want to see a Production build of your app with Universal (locally), you can simply run:
378
+
379
+
```bash
380
+
npm run build:dynamic && npm run serve:dynamic
198
381
```
199
382
200
-
## Caveats
383
+
Enjoy!
201
384
202
-
* Lazy loading is not yet supported, but coming very soon. Currently lazy loaded routes aren't available for prerendering, and you will get a `System is not defined` error.
203
-
* The bundle produced has a hash in the filename from webpack. When deploying this to a production server, you will need to ensure the correct bundle is required, either by renaming the file or passing the bundle name as an argument to your server.
385
+
Once again to see a working version of everything, check out the [universal-starter](https://github.com/angular/universal-starter/tree/master/cli).
0 commit comments