fix: more speedup hopefully
This commit is contained in:
@@ -679,7 +679,7 @@ export class BlogGenerationEngine {
|
|||||||
reportUnitProgress('Assets copied');
|
reportUnitProgress('Assets copied');
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderRoute = this.createSharedRouteRenderer(options, maxPostsPerPage);
|
const renderRoute = this.createSharedRouteRenderer(options, maxPostsPerPage, publishedPosts);
|
||||||
|
|
||||||
let pagesGenerated = 0;
|
let pagesGenerated = 0;
|
||||||
|
|
||||||
@@ -1285,7 +1285,7 @@ export class BlogGenerationEngine {
|
|||||||
const htmlDir = path.join(options.dataDir, 'html');
|
const htmlDir = path.join(options.dataDir, 'html');
|
||||||
await fs.mkdir(htmlDir, { recursive: true });
|
await fs.mkdir(htmlDir, { recursive: true });
|
||||||
|
|
||||||
const renderRoute = this.createSharedRouteRenderer(options, maxPostsPerPage);
|
const renderRoute = this.createSharedRouteRenderer(options, maxPostsPerPage, publishedPosts);
|
||||||
const onPageGenerated = (_message: string) => {
|
const onPageGenerated = (_message: string) => {
|
||||||
// no-op for applyValidation
|
// no-op for applyValidation
|
||||||
};
|
};
|
||||||
@@ -1440,6 +1440,7 @@ export class BlogGenerationEngine {
|
|||||||
private createSharedRouteRenderer(
|
private createSharedRouteRenderer(
|
||||||
options: BlogGenerationOptions,
|
options: BlogGenerationOptions,
|
||||||
maxPostsPerPage: number,
|
maxPostsPerPage: number,
|
||||||
|
publishedPostsForLookup: PostData[] = [],
|
||||||
): (pathname: string) => Promise<string | null> {
|
): (pathname: string) => Promise<string | null> {
|
||||||
const metadata: ProjectMetadata = {
|
const metadata: ProjectMetadata = {
|
||||||
name: options.projectName,
|
name: options.projectName,
|
||||||
@@ -1464,6 +1465,16 @@ export class BlogGenerationEngine {
|
|||||||
const postsByFilterPromiseCache = new Map<string, Promise<PostData[]>>();
|
const postsByFilterPromiseCache = new Map<string, Promise<PostData[]>>();
|
||||||
const publishedSnapshotByIdPromiseCache = new Map<string, Promise<PostData | null>>();
|
const publishedSnapshotByIdPromiseCache = new Map<string, Promise<PostData | null>>();
|
||||||
type PostFilterInput = Parameters<typeof this.postEngine.getPostsFiltered>[0];
|
type PostFilterInput = Parameters<typeof this.postEngine.getPostsFiltered>[0];
|
||||||
|
const publishedBySlugIndex = new Map<string, PostData[]>();
|
||||||
|
|
||||||
|
for (const post of publishedPostsForLookup) {
|
||||||
|
const existing = publishedBySlugIndex.get(post.slug);
|
||||||
|
if (existing) {
|
||||||
|
existing.push(post);
|
||||||
|
} else {
|
||||||
|
publishedBySlugIndex.set(post.slug, [post]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const serializeFilter = (filter: PostFilterInput): string => {
|
const serializeFilter = (filter: PostFilterInput): string => {
|
||||||
const normalizeValue = (value: unknown): unknown => {
|
const normalizeValue = (value: unknown): unknown => {
|
||||||
@@ -1506,6 +1517,24 @@ export class BlogGenerationEngine {
|
|||||||
publishedSnapshotByIdPromiseCache.set(postId, promise);
|
publishedSnapshotByIdPromiseCache.set(postId, promise);
|
||||||
return promise;
|
return promise;
|
||||||
},
|
},
|
||||||
|
findPublishedBySlug: async (slug: string, dateFilter?: { year: number; month: number }) => {
|
||||||
|
const candidates = publishedBySlugIndex.get(slug);
|
||||||
|
if (!candidates || candidates.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dateFilter) {
|
||||||
|
return candidates[0] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const match = candidates.find((candidate) => {
|
||||||
|
const createdAt = candidate.createdAt;
|
||||||
|
return createdAt.getFullYear() === dateFilter.year
|
||||||
|
&& createdAt.getMonth() === dateFilter.month;
|
||||||
|
});
|
||||||
|
|
||||||
|
return match ?? null;
|
||||||
|
},
|
||||||
getPost: (postId: string) => this.postEngine.getPost(postId),
|
getPost: (postId: string) => this.postEngine.getPost(postId),
|
||||||
hasPublishedVersion: (postId: string) => this.postEngine.hasPublishedVersion(postId),
|
hasPublishedVersion: (postId: string) => this.postEngine.hasPublishedVersion(postId),
|
||||||
setProjectContext: (projectId: string, dataDir?: string) => {
|
setProjectContext: (projectId: string, dataDir?: string) => {
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ interface PostEngineContract {
|
|||||||
getPost: (id: string) => Promise<PostData | null>;
|
getPost: (id: string) => Promise<PostData | null>;
|
||||||
hasPublishedVersion: (id: string) => Promise<boolean>;
|
hasPublishedVersion: (id: string) => Promise<boolean>;
|
||||||
getPublishedVersion: (id: string) => Promise<PostData | null>;
|
getPublishedVersion: (id: string) => Promise<PostData | null>;
|
||||||
|
findPublishedBySlug?: (slug: string, dateFilter?: { year: number; month: number }) => Promise<PostData | null>;
|
||||||
setProjectContext: (projectId: string, dataDir?: string) => void;
|
setProjectContext: (projectId: string, dataDir?: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -522,6 +523,13 @@ export class PreviewServer {
|
|||||||
private async findPublishedPostBySlug(slug: string, dateFilter?: { year: number; month: number }): Promise<PostData | null> {
|
private async findPublishedPostBySlug(slug: string, dateFilter?: { year: number; month: number }): Promise<PostData | null> {
|
||||||
if (!slug) return null;
|
if (!slug) return null;
|
||||||
|
|
||||||
|
if (this.postEngine.findPublishedBySlug) {
|
||||||
|
const directMatch = await this.postEngine.findPublishedBySlug(slug, dateFilter);
|
||||||
|
if (directMatch) {
|
||||||
|
return directMatch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const filter: PostFilter = {
|
const filter: PostFilter = {
|
||||||
...(dateFilter ? { year: dateFilter.year, month: dateFilter.month } : {}),
|
...(dateFilter ? { year: dateFilter.year, month: dateFilter.month } : {}),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -613,6 +613,33 @@ describe('BlogGenerationEngine', () => {
|
|||||||
expect(mockMediaEngine.getAllMedia).toHaveBeenCalledTimes(1);
|
expect(mockMediaEngine.getAllMedia).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('avoids per-route snapshot queries for single-post generation', async () => {
|
||||||
|
const posts: PostData[] = [];
|
||||||
|
for (let i = 0; i < 6; i += 1) {
|
||||||
|
posts.push(makePost({
|
||||||
|
id: `single-${i}`,
|
||||||
|
slug: `single-${i}`,
|
||||||
|
createdAt: new Date(`2025-${String(i + 1).padStart(2, '0')}-15T10:00:00Z`),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
setupPosts(posts);
|
||||||
|
|
||||||
|
const { BlogGenerationEngine } = await import('../../src/main/engine/BlogGenerationEngine');
|
||||||
|
const engine = new BlogGenerationEngine();
|
||||||
|
|
||||||
|
await engine.generate({
|
||||||
|
projectId: 'test',
|
||||||
|
projectName: 'Test Blog',
|
||||||
|
dataDir: tempDir,
|
||||||
|
baseUrl: 'https://example.com',
|
||||||
|
sections: ['single'],
|
||||||
|
}, vi.fn());
|
||||||
|
|
||||||
|
const filteredCallCount = mockPostEngine.getPostsFiltered.mock.calls.length;
|
||||||
|
expect(filteredCallCount).toBeLessThanOrEqual(8);
|
||||||
|
});
|
||||||
|
|
||||||
it('validates sitemap against html folder without rendering missing pages', async () => {
|
it('validates sitemap against html folder without rendering missing pages', async () => {
|
||||||
const posts = [
|
const posts = [
|
||||||
makePost({
|
makePost({
|
||||||
|
|||||||
Reference in New Issue
Block a user