我一直在使用 Angular 2 Universal进行服务器端预渲染。
但是具有直接 html 模板并通过templateUrl引用它们的组件不会预渲染(仅通过 url。使用模板:'...' 一切都很好),但客户端仍然加载。我正在使用asp.net 核心服务器和system.js。
package.json 的一部分:
"dependencies": {
"@angular/common": "^2.0.0-rc.4",
"@angular/compiler": "^2.0.0-rc.4",
"@angular/core": "^2.0.0-rc.4",
"@angular/forms": "^0.2.0",
"@angular/http": "^2.0.0-rc.4",
"@angular/platform-browser": "^2.0.0-rc.4",
"@angular/platform-browser-dynamic": "^2.0.0-rc.4",
"@angular/platform-server": "^2.0.0-rc.4",
"@angular/router": "^3.0.0-alpha.8",
"angular2-express-engine": "^0.15.3",
"angular2-hapi-engine": "^0.15.0",
"angular2-universal": "^0.104.5",
"angular2-universal-polyfills": "^0.4.1",
"aspnet-prerendering": "^1.0.1",
"bootstrap": "^3.3.5",
"css": "^2.2.1",
"es6-module-loader": "^0.17.11",
"es6-shim": "^0.35.0",
"isomorphic-fetch": "^2.2.1",
"less": "^2.5.3",
"parse5": "^1.5.0",
"path": "^0.12.7",
"preboot": "^2.1.2",
"reflect-metadata": "^0.1.3",
"rxjs": "5.0.0-beta.6",
"systemjs": "^0.19.3",
"traceur": "0.0.111",
"zone.js": "^0.6.12"
},
引导服务器.ts:
import 'angular2-universal/polyfills';
import { APP_BASE_HREF } from '@angular/common';
import * as ngCore from '@angular/core';
import * as ngRouter from '@angular/router';
import * as ngUniversal from 'angular2-universal';
import { BASE_URL, ORIGIN_URL, REQUEST_URL } from 'angular2-universal/common';
import { AppComponent } from './components/app.component';
import { routes } from './components/app.routes';
const bootloader = ngUniversal.bootloader({
async: true,
preboot: false,
platformProviders: [
ngCore.provide(APP_BASE_HREF, { useValue: '/' }),
]
});
export default function (params: any): Promise<{ html: string, globals?: any }> {
const config: ngUniversal.AppConfig = {
directives: [AppComponent],
providers: [
ngCore.provide(ORIGIN_URL, { useValue: params.origin }),
ngCore.provide(REQUEST_URL, { useValue: params.url }),
...ngUniversal.NODE_HTTP_PROVIDERS,
ngRouter.provideRouter(routes),
...ngUniversal.NODE_LOCATION_PROVIDERS,
],
// TODO: Render just the <app> component instead of wrapping it inside an extra HTML document
// Waiting on https://github.com/angular/universal/issues/347
template: '<!DOCTYPE html>\n<html><head></head><body><app></app></body></html>'
};
return bootloader.serializeApplication(config).then(html => {
return { html };
});
}
索引.cshtml:
<app asp-prerender-module="wwwroot/app/boot-server">Loading...</app>
@section scripts {
<script src="~/lib/zone.js/dist/zone.min.js"></script>
<script src="~/lib/reflect-metadata/Reflect.js"></script>
<script src="~/lib/traceur/bin/traceur-runtime.js"></script>
<script src="~/lib/systemjs/dist/system.src.js"></script>
<script src="~/system.config.js"></script>
<script src="~/lib/rxjs/bundles/Rx.js"></script>
<script>System.import('./app/boot-client');</script>
}
app.component.ts:
import * as ng from '@angular/core';
import * as router from '@angular/router';
@ng.Component({
selector: 'app',
templateUrl: './app/components/app.template.html',
directives: [router.ROUTER_DIRECTIVES]
})
export class AppComponent {
}
应用程序.routes.ts
import { RouterConfig } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { DashboardComponent } from './dashboard/dashboard.component';
import { SignInComponent } from './signin/signin.component';
import { SignUpComponent } from './signup/signup.component';
import { PageNotFoundComponent } from './pagenotfound/pagenotfound.component';
export const routes: RouterConfig = [
{ path: '', component: HomeComponent },
{ path: 'dashboard', component: DashboardComponent },
{ path: 'sign-in', component: SignInComponent },
{ path: 'sign-up', component: SignUpComponent },
{ path: '**', component: PageNotFoundComponent }
];
home.component.ts:
import * as ng from '@angular/core';
@ng.Component({
templateUrl: './app/components/home/home.template.html',
})
export class HomeComponent {
}
app.template.html:
<router-outlet></router-outlet>
<div *ngIf="globalErrors" class="container">
<div *ngIf="globalErrors.length > 0" class="alert alert-danger fade in">
<a (click)="clearErrors()" class="close" aria-label="close">×</a>
error...
</div>
</div>
content of app.component.ts
home.template.html:
<h1>Hello, world!</h1>
<p>Welcome to your new single-page application, built with:</p>
<ul>
<li><a href='https://get.asp.net/'>ASP.NET Core</a> and <a href='https://msdn.microsoft.com/en-us/library/67ef8sbd.aspx'>C#</a> for cross-platform server-side code</li>
<li><a href='https://angular.io/'>Angular 2</a> and <a href='http://www.typescriptlang.org/'>TypeScript</a> for client-side code</li>
<li><a href='https://webpack.github.io/'>Webpack</a> for building and bundling client-side resources</li>
<li><a href='http://getbootstrap.com/'>Bootstrap</a> for layout and styling</li>
</ul>
<p>To help you get started, we've also set up:</p>
<ul>
<li><strong>Client-side navigation</strong>. For example, click <em>Counter</em> then <em>Back</em> to return here.</li>
<li><strong>Server-side prerendering</strong>. For faster initial loading and improved SEO, your Angular 2 app is prerendered on the server. The resulting HTML is then transferred to the browser where a client-side copy of the app takes over.</li>
<li><strong>Webpack dev middleware</strong>. In development mode, there's no need to run the <code>webpack</code> build tool. Your client-side resources are dynamically built on demand. Updates are available as soon as you modify any file.</li>
<li><strong>Hot module replacement</strong>. In development mode, you don't even need to reload the page after making most changes. Within seconds of saving changes to files, your Angular 2 app will be rebuilt and a new instance injected is into the page.</li>
<li><strong>Efficient production builds</strong>. In production mode, development-time features are disabled, and the <code>webpack</code> build tool produces minified static CSS and JavaScript files.</li>
</ul>
html 为空:
但我们可以看到成功的服务器端请求: