Angular Cli 现在在 1.3.0-rc.0 及更高版本中支持此功能。
您可以使用安装此版本
npm install -g @angular/cli
Angular Cli Wiki 中关于通用渲染的设置说明
我有一个演示应用程序,可以在 GitHub 上找到
来源: https ://github.com/joejordanbrown/angular-cli-universal
现场演示: https ://uixd.co.uk/open-source-software/angular-cli-universal/
第 1 步:创建新的 Angular Cli 应用程序
$ ng new angular-cli-universal
第 2 步:安装 @angular/platform-server
将 @angular/platform-server 安装到您的项目中。确保您使用与项目中其他 @angular 包相同的版本。
$ npm install --save-dev @angular/platform-server
或者
$ yarn add @angular/platform-server
第 3 步:为通用渲染准备您的应用
您需要做的第一件事是通过将 .withServerTransition() 和应用程序 ID 添加到 BrowserModule 导入中,使您的 AppModule 与 Universal 兼容:
src/app/app.module.ts:
@NgModule({
bootstrap: [AppComponent],
imports: [
// Add .withServerTransition() to support Universal rendering.
// The application ID can be any identifier which is unique on
// the page.
BrowserModule.withServerTransition({appId: 'my-app'}),
...
],
})
export class AppModule {}
接下来,在服务器上运行时专门为您的应用程序创建一个模块。建议将此模块称为 AppServerModule。
此示例将它与 app.module.ts 放在一个名为 app.server.module.ts 的文件中:
src/app/app.server.module.ts:
import {NgModule} from '@angular/core';
import {ServerModule} from '@angular/platform-server';
import {AppModule} from './app.module';
import {AppComponent} from './app.component';
@NgModule({
imports: [
// The AppServerModule should import your AppModule followed
// by the ServerModule from @angular/platform-server.
AppModule,
ServerModule,
],
// Since the bootstrapped component is not inherited from your
// imported AppModule, it needs to be repeated here.
bootstrap: [AppComponent],
})
export class AppServerModule {}
第 4 步:创建一个服务器主文件和 tsconfig 来构建它
为您的通用捆绑包创建主文件。这个文件只需要导出你的 AppServerModule。它可以进入src。此示例调用此文件 main.server.ts:
src/main.server.ts:
export {AppServerModule} from './app/app.server.module';
将 tsconfig.app.json 复制到 tsconfig-server.json 并将其更改为使用“commonjs”的“模块”目标构建。
为“angularCompilerOptions”添加一个部分并将“entryModule”设置为您的 AppServerModule,指定为导入的路径,其中包含符号名称的哈希 (#)。在此示例中,这将是 src/app/app.server.module#AppServerModule。
src/tsconfig.server.json:
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/app",
"baseUrl": "./",
// Set the module format to "commonjs":
"module": "commonjs",
"types": []
},
"exclude": [
"test.ts",
"**/*.spec.ts"
],
// Add "angularCompilerOptions" with the AppServerModule you wrote
// set as the "entryModule".
"angularCompilerOptions": {
"entryModule": "app/app.server.module#AppServerModule"
}
}
第 5 步:创建 NodeJS 服务器文件
您需要创建一个 NodeJS 服务器来呈现和提供应用程序。此示例使用快递。
安装 express 和压缩
$ npm install --save express compression @nguniversal/express-engine
或者
$ yarn add express compression @nguniversal/express-engine
src/express.server.js:
const path = require('path');
const fs = require('fs');
const express = require('express');
const compression = require('compression');
const ngExpressEngine = require('@nguniversal/express-engine').ngExpressEngine;
require('zone.js/dist/zone-node');
require('rxjs/add/operator/filter');
require('rxjs/add/operator/map');
require('rxjs/add/operator/mergeMap');
var hash;
fs.readdirSync(__dirname).forEach(file => {
if (file.startsWith('main')) {
hash = file.split('.')[1];
}
});
const AppServerModuleNgFactory = require('./main.' + hash + '.bundle').AppServerModuleNgFactory;
const app = express();
const port = Number(process.env.PORT || 8080);
app.engine('html', ngExpressEngine({
baseUrl: 'http://localhost:' + port,
bootstrap: AppServerModuleNgFactory
}));
app.set('view engine', 'html');
app.set('views', path.join(__dirname, '/../browser'));
app.use(compression());
app.use('/', express.static(path.join(__dirname, '/../browser'), {index: false}));
app.get('/*', function (req, res) {
res.render('index', {
req: req,
// res: res
});
});
app.listen(port, function() {
console.log(`Listening at ${port}`);
});
第 6 步:在 .angular-cli.json 中创建一个新项目
在 .angular-cli.json 中,键“apps”下有一个数组。在那里复制您的客户端应用程序的配置,并将其作为新条目粘贴到数组中,并将附加键“平台”设置为“服务器”。
然后,删除“polyfills”键 - 服务器上不需要这些键并调整“main”和“tsconfig”以指向您在步骤 2 中编写的文件。最后,将“outDir”调整到新位置(这个示例使用 dist/server)。
.angular-cli.json:
{
...
"apps": [
{
// Keep your original application config the same apart from changing outDir to dist/browser.
// It will be app 0.
"outDir": "dist/browser",
},
{
// This is your server app. It is app 1.
"platform": "server",
"root": "src",
// Build to dist/server instead of dist. This prevents
// client and server builds from overwriting each other.
"outDir": "dist/server",
"assets": [
"assets",
"favicon.ico",
"express.server.js"
],
"index": "index.html",
// Change the main file to point to your server main.
"main": "main.server.ts",
// Remove polyfills.
// "polyfills": "polyfills.ts",
"test": "test.ts",
// Change the tsconfig to point to your server config.
"tsconfig": "tsconfig.server.json",
"testTsconfig": "tsconfig.spec.json",
"prefix": "app",
"styles": [
"styles.css"
],
"scripts": [],
"environmentSource": "environments/environment.ts",
"environments": {
"dev": "environments/environment.ts",
"prod": "environments/environment.prod.ts"
}
}
],
...
}
构建捆绑包
完成这些步骤后,您应该能够为您的应用程序构建服务器包,使用 --app 标志告诉 CLI 构建服务器包,在 .angular-cli 中的“apps”数组中引用其索引 1 .json:
# This builds the client application in dist/browser/
$ ng build --prod
...
# This builds the server bundle in dist/server/
$ ng build --prod --app 1
Date: 2017-07-24T22:42:09.739Z
Hash: 9cac7d8e9434007fd8da
Time: 4933ms
chunk {0} main.988d7a161bd984b7eb54.bundle.js (main) 9.49 kB [entry] [rendered]
chunk {1} styles.d41d8cd98f00b204e980.bundle.css (styles) 0 bytes [entry] [rendered]
启动快递服务器
$ node dist/server/express.server.js
查看 Angular Cli Wiki 了解更多详情
https://github.com/angular/angular-cli/wiki/stories-universal-rendering