ang*_*eor 13 offline lazy-loading webpack angular2-aot angular
我正在使用角度2懒惰路由.客户端使用AOT和angular-router-loader捆绑webpack2到延迟加载子级.当浏览器连接时,一切都按预期工作,即我可以成功地将路由器导航到延迟加载的模块,块成功加载,我可以查看组件等.
但是,如果我模拟断开连接(例如,通过使用脱机chrome开发人员工具选项)路由失败,正如预期的那样,因为它无法加载相关的块.错误是'加载块[块号]失败'
之后没有路由命令工作,就像路由器坏了.
我试图使用全局ErrorHandler处理错误.我的想法是,也许我可以在它破坏路由器之前捕获错误,但似乎到时候已经太晚了.当我发现错误时,路由器无法正常工作.
import { Injectable, ErrorHandler, Injector } from '@angular/core';
import { Router } from '@angular/router';
@Injectable()
export class CustomErrorHandler extends ErrorHandler {
constructor(private injector: Injector) {
super(false);
}
private get router(): Router {
return this.injector.get(Router, null);
}
public handleError(error: Error) {
if (/Loading chunk [\d]+ failed/.test(error.message)) {
console.info('Offline mode');
let router = this.router;
if (router) {
router.navigateByUrl('/offline').then(t => console.debug(t+'')).catch(t=> console.debug(t));
} else {
window.location.href = '/';
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
自定义错误处理程序有效,因为打印了"脱机模式"消息.注入也有效,路由器不为空,但是路由器导航不起作用,路由器承诺未解决也没有被拒绝.
我想要完成的是处理错误(例如向用户显示信息性消息)并同时使路由器处于工作状态,以便用户可以稍后导航(当恢复互联网连接时)没有重新加载整个页面.
为了查看这是否是一个角度路由器问题,我试图看看当尝试使用jit编译脱机工作时会发生什么.我使用:angular router plunker导航到登录选项卡,切换到离线并按下登录.当客户端尝试加载管理模块时,会记录许多"错误:XHR错误加载"错误.最终导航失败了,但是之后路由导航没有破坏.我能够导航到其他选项卡,在切换回在线后,我甚至能够导航到管理员.也许问题是angular-router-loader webpack插件如何尝试加载模块.
每当我walk狗并尝试在电梯中测试我的网站时,我都会遇到此错误。令人惊讶的是,没有更好的文档来处理错误-特别是github问题中的所有非解决方案。
随着中说,有是一个NavigationError从路由器的事件。因此,您可以拦截它,阻止正常的错误处理程序运行并显示一个弹出窗口。关于此事件的好处是它包含完整的尝试URL-而不是无用的Error: Uncaught (in promise): Error: Loading chunk common failed.错误。
这就是我的想法。
在app.component.ts(必须注入private router: Router)
initErrorHandler()从构造函数中调用该函数。
// filter router events of type NavigationError
navigationError$ = this.router.events.pipe
(filter((e): e is NavigationError => e instanceof NavigationError));
// Keep a reference to the error handled, so we can ignore it later
_errorHandled: any;
initErrorHandler()
{
this.navigationError$.subscribe((evt) =>
{
let showPopup = false;
// handle known error messages that can be retried
if (evt.error.message.startsWith('Loading chunk'))
{
showPopup = true;
}
else
{
debugger; // consider handling other messages
}
if (showPopup) {
// display a popup however you want...
// I use Angular Material, and popup is MY OWN dialog box service
this.popup.showChoicesDialog({
title: 'Network Error',
desc: 'Sorry we were unable to load that page',
fullscreen: true,
choices: [
{
action: () =>
{
// this is the important part - retry URL
this.router.navigateByUrl(evt.url)
},
buttonText: 'Retry'
}
]
});
// mark the error as handled to avoid global handler
this._errorHandled = evt.error;
}
// normal global error handler
this.zone.onError.subscribe((error: any) =>
{
// ignore errors that were already handled but couldn't be cancelled
if (error.rejection === this._errorHandled)
{
this._errorHandled = undefined;
return;
}
// Whatever you want to do here for true unhandled errors
console.warn(error);
});
}
Run Code Online (Sandbox Code Playgroud)
根据您的用户群,您需要更改消息和行为,但是通用方法似乎可行。
我尚不知道所有可能的NavigationError的完整范围,因此现在这仅能处理Loading chunk错误。如果您发现其他消息错误,请发表评论。
测试时请务必使用“离线”模式。在快速测试中,如果我启用了“脱机”模式以触发错误,然后尝试再次导航,则在禁用“脱机”后确实可以成功导航。
注意:有关“块错误”的许多讨论主题都与新部署后的缓存问题有关。我尚未解决这些问题,但是错误消息可能会有所不同,因此您可能会显示不同的弹出窗口。
小智 1
您可以预加载延迟加载的模块,以便在浏览器检测到不活动时将它们加载到客户端,这样它们就可以在离线模式下使用。
检查这里预加载所有模块:PreloadAllModules
您还可以创建自定义加载策略并仅预加载选定的模块:
自定义预加载.tsimport { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/mergeMap';
import { PreloadingStrategy, Route } from '@angular/router';
export class CustomPreloading implements PreloadingStrategy {
public preload(route: Route, fn: () => Observable<boolean>): Observable<boolean> {
if (route.data && route.data.preload) {
return Observable.of(true).flatMap((_: boolean) => fn());
} else {
return Observable.of(false);
}
}
}
Run Code Online (Sandbox Code Playgroud)
应用程序路由.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { CustomPreloading } from './custom-preloading';
const routes: Routes = [
{ ..other paths.. },
{ path: 'lazy', loadChildren: 'app/lazy/lazy.module#LazyModule', data: { preload: true } }
];
export const appRoutingProviders = [
CustomPreloading
];
@NgModule({
imports: [RouterModule.forRoot(routes, { preloadingStrategy: CustomPreloading })],
exports: [RouterModule]
})
export class AppRoutingModule { }
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2536 次 |
| 最近记录: |