Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"type": "module",
"scripts": {
"dev": "vite dev",
"build": "vite build",
"build": "ORIGIN=${ORIGIN:-https://www.maier.tech} vite build",
"start": "node build/index.js",
"preview": "vite preview",
"prepare": "svelte-kit sync || echo ''",
Expand Down
62 changes: 55 additions & 7 deletions src/lib/server/resolvers/resolvePost.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,48 @@ import type {
import { getAuthor, getLastCommit, getOgImageUrl, getTag } from '@maiertech/sveltekit-helpers';
import type { RequestEvent } from '@sveltejs/kit';

// Semaphore to limit concurrent API calls during prerendering
class Semaphore {
private permits: number;
private queue: Array<() => void> = [];

constructor(permits: number) {
this.permits = permits;
}

async acquire(): Promise<void> {
if (this.permits > 0) {
this.permits--;
return Promise.resolve();
}
return new Promise((resolve) => {
this.queue.push(resolve);
});
}

release(): void {
const resolve = this.queue.shift();
if (resolve) {
resolve();
} else {
this.permits++;
}
}

async execute<T>(fn: () => Promise<T>): Promise<T> {
await this.acquire();
try {
return await fn();
} finally {
this.release();
}
}
}

// Limit concurrent OG image and GitHub API calls to avoid overwhelming the APIs
const ogImageSemaphore = new Semaphore(3);
const githubSemaphore = new Semaphore(5);

export default async function ({
postMeta,
event
Expand Down Expand Up @@ -47,17 +89,23 @@ export default async function ({
template: 'maiertechPost',
title: postMeta.title
} as VcImageMeta;
ogImageUrl = await getOgImageUrl({ meta: ogImageMeta, apiKey: VIRALCARDS_API_KEY });
// Limit concurrent OG image API calls
ogImageUrl = await ogImageSemaphore.execute(() =>
getOgImageUrl({ meta: ogImageMeta, apiKey: VIRALCARDS_API_KEY })
);
}

// Resolve lastmodDate.
let lastmodDate: string | undefined = undefined;
const lastCommit = await getLastCommit({
owner: 'maiertech',
repo: 'website',
path: postMeta.filepath,
token: GITHUB_TOKEN
});
// Limit concurrent GitHub API calls
const lastCommit = await githubSemaphore.execute(() =>
getLastCommit({
owner: 'maiertech',
repo: 'website',
path: postMeta.filepath,
token: GITHUB_TOKEN
})
);

if (lastCommit) {
lastmodDate = lastCommit.commit.author?.date;
Expand Down
6 changes: 1 addition & 5 deletions src/routes/+page.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import type { NoteMeta, ResolvedPost } from '@maiertech/sveltekit-helpers';
import type { PageLoad } from './$types';

export const prerender = true;
// export const prerender = true;

export const load: PageLoad = async function ({ fetch }) {
// Read posts and notes.
// Do not reuse a `response` var to prevent this error:
// "Body is unusable: Body has already been read"

const notesResponse = await fetch('/api/notes/latest');
const notes = (await notesResponse.json()) as NoteMeta[];

Expand Down
3 changes: 3 additions & 0 deletions src/routes/api/authors/[id]/+server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { error, json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
import authors from './authors';

// We can't be sure that all routes are prerendered.
export const prerender = 'auto';

export const GET: RequestHandler = async ({ params }) => {
const id = params.id;
const author = resolve<AvatarMeta>(id, authors);
Expand Down
1 change: 0 additions & 1 deletion src/routes/api/notes/2025/+server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import noteVercelProtectionBypass from '$notes/(2025)/vercel-deployment-protecti
import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';

// Needs to be set explicitly because we prerender endpoint `/sitemap.xml`.
export const prerender = true;

export const GET: RequestHandler = async () => {
Expand Down
1 change: 0 additions & 1 deletion src/routes/api/notes/all/+server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import type { RequestHandler } from './$types';
import { json } from '@sveltejs/kit';
import type { NoteMeta } from '@maiertech/sveltekit-helpers';

// Needs to be set explicitly because we prerender endpoint `/sitemap.xml`.
export const prerender = true;

// Return all notes.
Expand Down
3 changes: 1 addition & 2 deletions src/routes/api/notes/latest/+server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import type { RequestHandler } from './$types';
import { json } from '@sveltejs/kit';
import type { NoteMeta } from '@maiertech/sveltekit-helpers';

// No need to set `export const prerender = true;`.
// Prerendering is triggered by `/`, which uses this endpoint and iself is prerendered.
export const prerender = true;

// Return latest notes (up to 20).
export const GET: RequestHandler = async ({ fetch }) => {
Expand Down
4 changes: 2 additions & 2 deletions src/routes/api/posts/2021/+server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import postMoveYourIdeToTheCloud from '$posts/(2021)/move-your-ide-to-the-cloud-
import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';

// Needs to be set explicitly because we prerender endpoint `/sitemap.xml`.
export const prerender = true;
// Nested prerendering breaks build on Railway.
// export const prerender = true;

export const GET: RequestHandler = async (event) => {
// Sort order: latest first.
Expand Down
4 changes: 2 additions & 2 deletions src/routes/api/posts/2022/+server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import postAtAndHashtagSymbols from '$posts/(2022)/using-the-at-and-hash-symbols
import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';

// Needs to be set explicitly because we prerender endpoint `/sitemap.xml`.
export const prerender = true;
// Nested prerendering breaks build on Railway.
// export const prerender = true;

export const GET: RequestHandler = async (event) => {
// Sort order: latest first.
Expand Down
4 changes: 2 additions & 2 deletions src/routes/api/posts/2023/+server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import postStackBlitzCodeflowBeta from '$posts/(2023)/is-stackblitz-codeflow-bet
import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';

// Needs to be set explicitly because we prerender endpoint `/sitemap.xml`.
export const prerender = true;
// Nested prerendering breaks build on Railway.
// export const prerender = true;

export const GET: RequestHandler = async (event) => {
// Sort order: latest first.
Expand Down
4 changes: 2 additions & 2 deletions src/routes/api/posts/2024/+server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import postCopilotContext from '$posts/(2024)/github-copilot-context/meta';
import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';

// Needs to be set explicitly because we prerender endpoint `/sitemap.xml`.
export const prerender = true;
// Nested prerendering breaks build on Railway.
// export const prerender = true;

export const GET: RequestHandler = async (event) => {
// Sort order: latest first.
Expand Down
3 changes: 2 additions & 1 deletion src/routes/api/posts/2025/+server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import postManagingEnvVarsWithVercel from '$posts/(2025)/managing-environment-va
import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';

export const prerender = true;
// Nested prerendering breaks build on Railway.
// export const prerender = true;

export const GET: RequestHandler = async (event) => {
// Sort order: latest first.
Expand Down
4 changes: 2 additions & 2 deletions src/routes/api/posts/all/+server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import type { ResolvedPost } from '@maiertech/sveltekit-helpers';
import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';

// Needs to be set explicitly because we prerender endpoint `/sitemap.xml`.
export const prerender = true;
// Nested prerendering breaks build on Railway.
// export const prerender = true;

// Return all posts.
export const GET: RequestHandler = async ({ fetch }) => {
Expand Down
4 changes: 2 additions & 2 deletions src/routes/api/posts/latest/+server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import type { ResolvedPost } from '@maiertech/sveltekit-helpers';
import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';

// No need to set `export const prerender = true;`.
// Prerendering is triggered by `/`, which uses this endpoint and iself is prerendered.
// Nested prerendering breaks build on Railway.
// export const prerender = true;

// Return latest posts (up to 10).
export const GET: RequestHandler = async ({ fetch }) => {
Expand Down
3 changes: 2 additions & 1 deletion src/routes/api/posts/rss/+server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import type { ResolvedPost } from '@maiertech/sveltekit-helpers';
import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';

export const prerender = true;
// Nested prerendering breaks build on Railway.
// export const prerender = true;

export const GET: RequestHandler = async ({ fetch }) => {
const response = await fetch('/api/posts/latest');
Expand Down
3 changes: 1 addition & 2 deletions src/routes/api/tags/[id]/+server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ import { error, json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
import tags from './tags';

// Include this endpoint into the manifest.
// This ensures that dynamic calls for tags that have not been prerendered still work.
// We can't be sure that all routes are prerendered.
export const prerender = 'auto';

export const GET: RequestHandler = async ({ params }) => {
Expand Down
3 changes: 2 additions & 1 deletion src/routes/notes/rss.xml/+server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { ORIGIN } from '$env/static/private';
import type { RssItem } from '$lib/types';
import type { RequestHandler } from '@sveltejs/kit';

export const prerender = true;
// Prerendering turned off because notes endpoints are not prerendered.
// export const prerender = true;

export const GET: RequestHandler = async ({ fetch }) => {
const response = await fetch('/api/notes/rss');
Expand Down
3 changes: 2 additions & 1 deletion src/routes/posts/rss.xml/+server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { ORIGIN } from '$env/static/private';
import type { RssItem } from '$lib/types';
import type { RequestHandler } from '@sveltejs/kit';

export const prerender = true;
// Prerendering turned off because posts endpoints are not prerendered.
// export const prerender = true;

export const GET: RequestHandler = async ({ fetch }) => {
const response = await fetch('/api/posts/rss');
Expand Down
3 changes: 2 additions & 1 deletion src/routes/rss.xml/+server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { ORIGIN } from '$env/static/private';
import type { RssItem } from '$lib/types';
import type { RequestHandler } from '@sveltejs/kit';

export const prerender = true;
// Prerendering turned off because posts endpoints are not prerendered.
// export const prerender = true;

export const GET: RequestHandler = async ({ fetch }) => {
// Read posts and notes.
Expand Down
3 changes: 2 additions & 1 deletion src/routes/sitemap.xml/+server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { ORIGIN } from '$env/static/private';
import type { NoteMeta, ResolvedPost } from '@maiertech/sveltekit-helpers';
import type { RequestHandler } from './$types';

export const prerender = true;
// Prerendering turned off because posts and notes endpoints are not prerendered.
// export const prerender = true;

export const GET: RequestHandler = async ({ fetch }) => {
// Fetch posts. `/api/posts/all` includes `lastmodDate`.
Expand Down