fix(ssr): remove spider-only gate — serve full SSR to all users #13

Closed
robot wants to merge 1 commits from fix/ssr-for-all-users into main
pull from: fix/ssr-for-all-users
2 changed files with 27 additions and 30 deletions

No files matched your search

+16 -18
View File
@@ -33,28 +33,26 @@ vi.mock('./angular-app-engine-manifest.mjs', () => ({
})); }));
describe('SSR server — server.ts', () => { describe('SSR server — server.ts', () => {
it('should export a request handler', async () => { it('should route all requests through Angular SSR engine (no spider gate)', async () => {
const fs = require('fs');
const content = fs.readFileSync('./server.ts', 'utf-8');
expect(content).toContain('requestHandler(req, res,');
// Should NOT have spider-only SSR gate
expect(content).not.toContain('if (!isSpider(userAgent))');
expect(content).not.toContain('isSpider');
});
it('should still have serveCsrShell as a fallback for when SSR engine fails', async () => {
const fs = require('fs');
const content = fs.readFileSync('./server.ts', 'utf-8');
expect(content).toContain('serveCsrShell');
});
it('should have request handler export', async () => {
const mod = await import('./server'); const mod = await import('./server');
expect(mod.requestHandler).toBeDefined(); expect(mod.requestHandler).toBeDefined();
}); });
it('should have spider detection imports and serveCsrShell', async () => {
const fs = require('fs');
const content = fs.readFileSync('./server.ts', 'utf-8');
expect(content).toContain('isSpider');
expect(content).toContain('getUserAgent');
expect(content).toContain('serveCsrShell');
expect(content).toContain('spider_detection');
});
it('should gate SSR behind spider detection', async () => {
const fs = require('fs');
const content = fs.readFileSync('./server.ts', 'utf-8');
// Verify the spider detection gate exists
expect(content).toContain("if (!isSpider(userAgent))");
expect(content).toContain('serveCsrShell(res)');
});
it('should inject fresh station config as window.__STATION_CONFIG', async () => { it('should inject fresh station config as window.__STATION_CONFIG', async () => {
const fs = require('fs'); const fs = require('fs');
const content = fs.readFileSync('./server.ts', 'utf-8'); const content = fs.readFileSync('./server.ts', 'utf-8');
+11 -12
View File
@@ -8,7 +8,6 @@ import * as fs from 'node:fs';
import * as http from 'node:http'; import * as http from 'node:http';
import * as https from 'node:https'; import * as https from 'node:https';
import * as path from 'node:path'; import * as path from 'node:path';
import { isSpider, getUserAgent } from './spider_detection';
/** /**
* Manually import and register the Angular app engine manifest. * Manually import and register the Angular app engine manifest.
@@ -263,17 +262,17 @@ if (isMainModule(import.meta.url)) {
const server = http.createServer(); const server = http.createServer();
server.on('request', async (req, res) => { server.on('request', async (req, res) => {
try { try {
// ── Spider detection gate ────────────────────────── // ── SSR rendering for all users ────────────────────
// Only search engine spiders get full SSR rendering. // Every user — spiders and regular browsers — gets full
// Regular users receive the CSR app shell from disk, // Angular SSR rendering. The SSR engine (main.server.ts)
// enhanced with fresh station config injected at runtime. // fetches fresh station config from the API via APP_INITIALIZER
const userAgent = getUserAgent(req.headers); // before rendering, so the first paint carries real content,
if (!isSpider(userAgent)) { // colors, and assets. No CSR shell flash, no blank gap.
await serveCsrShell(res); //
return; // NOTE: The spider-only SSR gate was removed because serving
} // a CSR shell (empty <app-root>) to regular browsers caused
// a visible blank-to-content transition. The SSR engine is
// Spider — render full HTML via Angular SSR with live API data // fast enough to handle regular traffic.
await requestHandler(req, res, () => { await requestHandler(req, res, () => {
res.statusCode = 404; res.statusCode = 404;
res.end('Not Found'); res.end('Not Found');