Angular Universal 和 Express 的慢速 TTFB
Slow TTFB with Angular Universal and Express
我将此作为自答问题发布,因为我在调试此问题时没有在网络上找到任何有用的信息。
出于某种原因,我的 Angular 7 应用程序的 SSR 版本始终具有大约 5 秒的 TTFB。我正在使用 Angular Universal 的标准设置,使用 Express 进行一些修改,如下所示:
// These are important and needed before anything else
import 'zone.js/dist/zone-node';
import 'reflect-metadata';
import { renderModuleFactory } from '@angular/platform-server';
import { enableProdMode } from '@angular/core';
import * as express from 'express';
import { join } from 'path';
import { readFileSync } from 'fs';
import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';
// Faster server renders w/ Prod mode (dev mode never needed)
enableProdMode();
// Express server
const compression = require('compression');
const app = express();
app.use(compression());
const PORT = process.env.PORT || 4000;
const DIST_FOLDER = join(process.cwd(), 'dist');
const domino = require('domino');
const template = readFileSync(join(DIST_FOLDER , 'browser', 'index.html')).toString();
const win = domino.createWindow(template);
global['window'] = win;
global['Node'] = win.Node;
global['navigator'] = win.navigator;
global['Event'] = win.Event;
global['KeyboardEvent'] = win.Event;
global['MouseEvent'] = win.Event;
global['Event']['prototype'] = win.Event.prototype;
global['document'] = win.document;
// * NOTE :: leave this as require() since this file is built Dynamically from webpack
const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/server/main');
app.engine('html', (_, options, callback) => {
renderModuleFactory(AppServerModuleNgFactory, {
// Our index.html
document: template,
url: options.req.url,
// DI so that we can get lazy-loading to work differently (since we need it to just instantly render it)
extraProviders: [
provideModuleMap(LAZY_MODULE_MAP)
]
}).then(html => {
callback(null, html);
});
});
app.set('view engine', 'html');
app.set('views', join(DIST_FOLDER, 'browser'));
// Server static files from /browser
app.get('*.*', express.static(join(DIST_FOLDER, 'browser')));
// All regular routes use the Universal engine
app.get('*', (req, res) => {
res.render(join(DIST_FOLDER, 'browser', 'index.html'), { req });
});
// Start up the Node server
app.listen(PORT, () => {
console.log(`Node server listening on http://localhost:${PORT}`);
});
我试过在服务器上缓存页面并删除非标准 Domino 内容以使其与教程一样,但没有任何改变 TTFB。这让我相信应用程序代码中的某些东西可能会减慢它的速度。有什么想法吗?
仔细想想,我记得我在 pre-loading 模块上添加了 5 秒的延迟,这样从应用程序跳出的用户就不必下载所有延迟加载的包.代码是这样的:
import { PreloadingStrategy } from "@angular/router";
import { Route } from "@angular/router";
import { RouterModule } from "@angular/router";
import { Routes } from "@angular/router";
import { NgModule } from "@angular/core";
import { Observable, timer } from "rxjs";
import { of } from 'rxjs/internal/observable/of';
import { flatMap } from "rxjs/internal/operators";
export class PreloadPublicModules implements PreloadingStrategy {
preload(route : Route, load : Function) : Observable<any> {
const loadRoute = (delay) => delay ? timer(5000).pipe(flatMap(_ => load())) : load();
return route.data && route.data.preload ? loadRoute(5000) : of(null);
}
}
const routes : Routes = [
{ path: '', loadChildren: "app/public/home/home.module#HomeModule", data: { preload: true } },
{ path: 'about', loadChildren: "app/public/about/about.module#AboutModule", data: { preload: true } },
{ path: 'contact', loadChildren: "app/public/contact/contact.module#ContactModule", data: { preload: true } },
{ path: 'dashboard', loadChildren: "app/internal/dashboard/dashboard.module#DashboardModule", data: { preload: false } },
];
@NgModule({
imports : [ RouterModule.forRoot(routes, { preloadingStrategy: PreloadPublicModules }) ],
exports : [ RouterModule ],
providers : [ PreloadPublicModules ]
})
export class AppRoutingModule { }
移除延迟解决了 SSR 部分的问题;它不再有 5s TTFB。 PreloadPublicModules
函数现在是:
export class PreloadPublicModules implements PreloadingStrategy {
preload(route : Route, load : Function) : Observable<any> {
return route.data && route.data.preload ? load() : of(null);
}
}
我将此作为自答问题发布,因为我在调试此问题时没有在网络上找到任何有用的信息。
出于某种原因,我的 Angular 7 应用程序的 SSR 版本始终具有大约 5 秒的 TTFB。我正在使用 Angular Universal 的标准设置,使用 Express 进行一些修改,如下所示:
// These are important and needed before anything else
import 'zone.js/dist/zone-node';
import 'reflect-metadata';
import { renderModuleFactory } from '@angular/platform-server';
import { enableProdMode } from '@angular/core';
import * as express from 'express';
import { join } from 'path';
import { readFileSync } from 'fs';
import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';
// Faster server renders w/ Prod mode (dev mode never needed)
enableProdMode();
// Express server
const compression = require('compression');
const app = express();
app.use(compression());
const PORT = process.env.PORT || 4000;
const DIST_FOLDER = join(process.cwd(), 'dist');
const domino = require('domino');
const template = readFileSync(join(DIST_FOLDER , 'browser', 'index.html')).toString();
const win = domino.createWindow(template);
global['window'] = win;
global['Node'] = win.Node;
global['navigator'] = win.navigator;
global['Event'] = win.Event;
global['KeyboardEvent'] = win.Event;
global['MouseEvent'] = win.Event;
global['Event']['prototype'] = win.Event.prototype;
global['document'] = win.document;
// * NOTE :: leave this as require() since this file is built Dynamically from webpack
const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/server/main');
app.engine('html', (_, options, callback) => {
renderModuleFactory(AppServerModuleNgFactory, {
// Our index.html
document: template,
url: options.req.url,
// DI so that we can get lazy-loading to work differently (since we need it to just instantly render it)
extraProviders: [
provideModuleMap(LAZY_MODULE_MAP)
]
}).then(html => {
callback(null, html);
});
});
app.set('view engine', 'html');
app.set('views', join(DIST_FOLDER, 'browser'));
// Server static files from /browser
app.get('*.*', express.static(join(DIST_FOLDER, 'browser')));
// All regular routes use the Universal engine
app.get('*', (req, res) => {
res.render(join(DIST_FOLDER, 'browser', 'index.html'), { req });
});
// Start up the Node server
app.listen(PORT, () => {
console.log(`Node server listening on http://localhost:${PORT}`);
});
我试过在服务器上缓存页面并删除非标准 Domino 内容以使其与教程一样,但没有任何改变 TTFB。这让我相信应用程序代码中的某些东西可能会减慢它的速度。有什么想法吗?
仔细想想,我记得我在 pre-loading 模块上添加了 5 秒的延迟,这样从应用程序跳出的用户就不必下载所有延迟加载的包.代码是这样的:
import { PreloadingStrategy } from "@angular/router";
import { Route } from "@angular/router";
import { RouterModule } from "@angular/router";
import { Routes } from "@angular/router";
import { NgModule } from "@angular/core";
import { Observable, timer } from "rxjs";
import { of } from 'rxjs/internal/observable/of';
import { flatMap } from "rxjs/internal/operators";
export class PreloadPublicModules implements PreloadingStrategy {
preload(route : Route, load : Function) : Observable<any> {
const loadRoute = (delay) => delay ? timer(5000).pipe(flatMap(_ => load())) : load();
return route.data && route.data.preload ? loadRoute(5000) : of(null);
}
}
const routes : Routes = [
{ path: '', loadChildren: "app/public/home/home.module#HomeModule", data: { preload: true } },
{ path: 'about', loadChildren: "app/public/about/about.module#AboutModule", data: { preload: true } },
{ path: 'contact', loadChildren: "app/public/contact/contact.module#ContactModule", data: { preload: true } },
{ path: 'dashboard', loadChildren: "app/internal/dashboard/dashboard.module#DashboardModule", data: { preload: false } },
];
@NgModule({
imports : [ RouterModule.forRoot(routes, { preloadingStrategy: PreloadPublicModules }) ],
exports : [ RouterModule ],
providers : [ PreloadPublicModules ]
})
export class AppRoutingModule { }
移除延迟解决了 SSR 部分的问题;它不再有 5s TTFB。 PreloadPublicModules
函数现在是:
export class PreloadPublicModules implements PreloadingStrategy {
preload(route : Route, load : Function) : Observable<any> {
return route.data && route.data.preload ? load() : of(null);
}
}