Angular Repository url:https://github.com/angular/angular-cli/issues/7477
现象:
I built a sample repo using angular-cli and followed the steps in the Universal Rendering story to enable server side rendering. The application loads well on running, but I see the client rendering also happening after the page is served from the server. So the page gets rendered from the server and then the content disappears for a second as the client rendering happens.
观察到 page 从服务器端 serve 之后,client side rendering 还会再次发生。有一瞬间的功夫,服务器端渲染的内容消失了,client rendering 接着发生。
有网友回复:
The server renders the page without any state and outputs static HTML to view in the browser while the angular application is being bootstrapped. A re-render when the application has been bootstrapped is required to use state saved in the browser such as logged in user information.
SSR 渲染出的是纯粹的 Static HTML
,没有任何状态,也无法响应用户的交互。
当应用在客户端完成 Boostrap 之后,re-render 是必要的,以便使用服务器端静态 HTML 里嵌入的通过 State Transfer 传递的业务数据(这些业务数据在 SSR 时通过服务器端执行的 AJAX,从 API server 读取)。
The initial page contains static HTML which needs to be replaced with your angular application once bootstrapped.
这些静态页面的内容,需要被 Angular 应用在客户端 Bootstrap 之后重新渲染的内容所替换。
To make the transfer state work, the Angular application must be bootstrapped after the DOM is loaded. This is because, the data transferred from the server is stored in an HTML element and this element should be accessible to Angular to get the data. Open the file main.ts and move the application bootstrap logic inside the DOMContentLoaded event as shown below:
因为 Transfer State 的工作机制是解析嵌入在 HTML 页面里的 DOM 元素,所以客户端渲染的 Angular 应用,需要等待 DOM 加载之后再进行 Bootstrap.
为此我们需要在 main.ts 文件里编写下面的代码:
document.addEventListener('DOMContentLoaded', () => {
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.log(err));
});
这段代码是Angular应用的入口点,它有以下作用:
- 等待文档加载完成:
document.addEventListener('DOMContentLoaded', ...)
表示在文档(DOM)加载完成后执行特定的操作。这是为了确保JavaScript代码在HTML文档完全加载后运行,以避免在DOM元素还未准备好的情况下执行操作,从而避免潜在的错误。 - 动态启动Angular应用:
platformBrowserDynamic().bootstrapModule(AppModule)
是Angular的核心方法之一,它用于动态启动(bootstrap)一个Angular应用。在这里,它将AppModule
作为应用的根模块来启动。 - 处理启动失败:
.catch(err => console.log(err))
表示在启动过程中如果出现错误,将错误信息打印到控制台。这是为了帮助开发人员调试应用并捕获潜在的问题。
让我们详细解释每个部分,并举例说明其作用:
1. 等待文档加载完成 (document.addEventListener('DOMContentLoaded', ...)
)
这是为了确保在HTML文档完全加载后再执行Angular应用的启动过程。当浏览器加载HTML页面时,它按照从上到下的顺序逐步构建DOM树。如果你的JavaScript代码在DOM还没有完全加载之前执行,那么它可能无法找到所需的DOM元素,导致错误或不稳定的行为。
例如,假设你的Angular应用需要在特定的HTML元素上渲染内容,如果你在DOM未加载完成时尝试访问这些元素,可能会出现问题。通过等待DOMContentLoaded
事件,你可以确保DOM已准备就绪,然后再执行Angular应用的启动。
document.addEventListener('DOMContentLoaded', () => {
// 在这里启动Angular应用
});
2. 动态启动Angular应用 (platformBrowserDynamic().bootstrapModule(AppModule)
)
这部分代码是启动Angular应用的核心。它使用了Angular的 platformBrowserDynamic
类的实例来动态启动一个Angular应用,然后将 AppModule
作为应用的根模块。这意味着你的Angular应用将从 AppModule
开始加载,并构建整个应用。
让我们来看一个示例,假设有一个名为 AppModule
的Angular模块,它定义了应用的根组件和其他相关配置。这是一个典型的Angular模块定义:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
@NgModule({
imports: [BrowserModule],
declarations: [AppComponent],
bootstrap: [AppComponent]
})
export class AppModule { }
在这个示例中,AppModule
使用 @NgModule
装饰器来定义模块,它引入了 BrowserModule
作为依赖,声明了根组件 AppComponent
,并将 AppComponent
标记为启动组件(bootstrap
属性)。这意味着 AppComponent
将成为应用的根组件。
在主要的 main.ts
文件中,我们使用 platformBrowserDynamic().bootstrapModule(AppModule)
来启动应用,这将启动整个应用并将 AppComponent
渲染到页面上。
document.addEventListener('DOMContentLoaded', () => {
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.log(err));
});
这段代码会在文档加载完成后,启动Angular应用,并且任何错误(如果有)都会被捕获并打印到控制台。
3. 处理启动失败 (.catch(err => console.log(err))
)
最后一部分代码是使用 .catch()
方法处理启动过程中可能出现的错误。在实际应用中,启动Angular应用可能会面临各种问题,如依赖注入失败、组件未找到、模块配置错误等。通过使用 .catch()
方法,你可以捕获这些错误并将它们记录到控制台,以便进行调试。
示例代码如下:
document.addEventListener('DOMContentLoaded', () => {
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.log(err));
});
在这个示例中,如果在启动应用过程中出现了任何错误,错误信息将被传递给 err
,然后使用 console.log()
打印到控制台,以便开发人员可以查看错误详情。
总结来说,这段代码的主要作用是等待文档加载完成后,动态启动Angular应用,并在启动过程中处理可能出现的错误。这是Angular应用的入口点,确保应用在稳定的环境中启动,并为开发人员提供了一种捕获和调试潜在问题的机制。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。