是的,我正在努力使用 Angular 应用程序外壳,因为我的应用程序路由中有一个通配符。我的项目是一个独立的 Angular 项目。我们该如何解决这个问题?
app.config.server.ts
文件:
import { mergeApplicationConfig, ApplicationConfig } from '@angular/core';
import { provideServerRendering } from '@angular/platform-server';
import { appConfig } from './app.config';
import { ROUTES } from '@angular/router';
import { AppShellComponent } from './app-shell/app-shell.component';
const serverConfig: ApplicationConfig = {
providers: [
provideServerRendering(),
{
provide: ROUTES,
multi: true,
useValue: [
{
path: 'shell',
component: AppShellComponent,
},
],
},
],
};
export const config = mergeApplicationConfig(appConfig, serverConfig);
我还经历过,如果我使用
APP_INITIALIZER
并尝试重定向到错误页面(基于我们的逻辑),App-shell 会导航到该错误页面并将该页面嵌入到我们的 HTML 中,而不是嵌入 app-shell 页面本身!怎么解决这个问题?!
app.config.ts
文件:
import { APP_INITIALIZER, ApplicationConfig, isDevMode } from '@angular/core';
import {
Router,
provideRouter,
withEnabledBlockingInitialNavigation,
} from '@angular/router';
import { appRoutes } from './app.routes';
function initAppFactoryConfig(router: Router) {
return () => new Promise((resolve, reject) => {
// We resolve the promise whatsoever! Because we want the app to complete
// its initialization... BUT based on our logic (e.g., if the file we're
// trying to load at initialization, couldn't get loaded), we may like to
// redirect to one of our app's pages and then resolve... In this case
// app-shell embeds the error page into the HTML instead!
router.navigate(['/error-loading']);
resolve(true);
});
}
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(appRoutes, withEnabledBlockingInitialNavigation()),
{
provide: APP_INITIALIZER,
useFactory: initAppFactoryConfig,
deps: [Router],
multi: true,
},
],
};
在 Angular 18 中,我通过在通配符路由中添加
canMatch
防护来解决这个问题,这样它只在客户端匹配。
import { Inject, Injectable, PLATFORM_ID } from '@angular/core';
import { CanMatch, Route, UrlSegment } from '@angular/router';
import { isPlatformServer } from '@angular/common';
@Injectable({
providedIn: 'root'
})
export class ClientOnlyGuard implements CanMatch {
constructor(@Inject(PLATFORM_ID) private platformId: Object) {}
canMatch(route: Route, segments: UrlSegment[]): boolean {
const isServer = isPlatformServer(this.platformId);
return !isServer;
}
}
然后...
{ path: '**', loadComponent: () => import('src/app/errors/not-found/not-found.component').then(x => x.NotFoundComponent), canMatch: [ClientOnlyGuard] },