Я недавно начал преобразовывать мое приложение Angular 7.2.0 в универсальное приложение Angular. Приложение успешно рендерится на стороне сервера и довольно быстро передает состояние на быстрых ПК и интернет-соединениях, но, к сожалению, до момента передачи на отображаемой странице отсутствуют какие-либо данные, обычно извлекаемые из API.
Я добавил serverURL
к предоставленному токену с сервера, и при рендеринге на стороне сервера все http-запросы выполняются с использованием полного URL-адреса. Однако, похоже, это не имеет значения, поскольку все http-вызовы отменяются до их завершения! Мой сервер не показывает вызовов к конечным точкам API, и клиент регистрирует ошибку {}
(которая по умолчанию отображается как [Error]
).
Я использую TransferStateModule
, а также TransferHttpCacheModule
, но пока ничего не получалось. Кажется, что рендер экспресс-движка просто не будет ждать асинхронных http-вызовов. Он влияет на вызовы http в ngOnInit
компонентов, constructor
s служб и любые в resolver
s, поэтому я не знаю, как еще получить данные.
Для таких вещей, как данные конфигурации, я вставляю необходимые поля в качестве токена и проверяю этот токен при рендеринге на стороне сервера, но не могу сделать это для всех данных в приложении.
Ниже приведены соответствующие разделы моего сервера и модулей приложения.
app.ts (узел экспресс-сервера)
app.get('*.*', express.static(APP_CONFIG.client_root, {maxAge: 0}));
// Render Angular Universal
if (APP_CONFIG.universal) {
// Our index.html we'll use as our template
const templateFile = HelpersService.tryLoad(join(APP_CONFIG.client_root, './index.html'));
const config = configService.getConfig();
const template = templateFile.toString();
const win = domino.createWindow(template);
const fakeanimation = {
value: () => {
return {
enumerable: true,
configurable: true
};
},
};
global['window'] = win;
global['document'] = {...win.document,
createElement: () => {},
body: {
...win.document.body,
style: {
...win.document.body.style,
transform: fakeanimation,
opacity: fakeanimation,
bottom: fakeanimation,
left: fakeanimation,
}
}
};
global['navigator'] = win.navigator;
global['location'] = win.location;
const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('../ssr/ssr.js');
app.engine('html', ngExpressEngine({
bootstrap: AppServerModuleNgFactory,
providers: [
provideModuleMap(LAZY_MODULE_MAP),
]
}));
app.set('view engine', 'html');
app.set('views', APP_CONFIG.client_root);
app.get('*', (req, res, next) => {
const protocol = res.locals.protocol || req.protocol;
const showPort = ((APP_CONFIG.port === 80 && protocol === 'http') || (protocol === 'https')) ? false : true;
const serverUrl = `${protocol}://${req.hostname}${showPort ? ':'+APP_CONFIG.port : ''}`;
res.render('index', {
req,
document: template,
url: req.url,
providers: [
{
provide: 'serverURL',
useValue: serverUrl
},
{
provide: 'SERVER_CONFIG',
useValue: config || {}
},
{
provide: 'SERVER_AUTH',
useValue: {signedIn: !!res.locals.auth}
},
]
});
});
}
app.module.ts
@NgModule({
bootstrap: [
AppComponent
],
imports: [
BrowserModule.withServerTransition({appId: 'myapp'}),
BrowserAnimationsModule,
SharedModule,
TransferHttpCacheModule,
BrowserTransferStateModule,
RouterModule.forRoot(
...
app.server.module.ts
@NgModule({
imports: [
// The AppServerModule should import your AppModule followed
// by the ServerModule from @angular/platform-server.
AppModule,
ServerModule,
ServerTransferStateModule,
ModuleMapLoaderModule // <-- *Important* to have lazy-loaded routes work
],
// Since the bootstrapped component is not inherited from your
// imported AppModule, it needs to be repeated here.
bootstrap: [AppComponent],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: ServerSideRequestInterceptor,
multi: true,
},
]
})
export class AppServerModule {}
ServerSideRequestInterceptor
читает токен инъекции serverURL
и добавляет его ко всем запросам, начиная с /
.
Мне кажется, я очень близок к тому, чтобы взломать это, но я не могу сказать, как заставить его ждать http-вызовов в моем приложении.
EDIT:
Вот репо, которое я сделал с рабочим универсальным и угловым 7:
https://github.com/swimmadude66/AngularPWASeed/tree/universal7