Skip to content

Commit b73e67c

Browse files
committed
improve performance
1 parent ece7c3d commit b73e67c

8 files changed

Lines changed: 122 additions & 9 deletions

File tree

app/layout.tsx

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Container from "@/components/ui/container";
22
import "./globals.css";
3-
import type { Metadata } from "next";
3+
import type { Metadata, Viewport } from "next";
44
import Header from "@/components/Header";
55
import Footer from "@/components/Footer";
66
import CookieBanner from "@/components/CookieBanner";
@@ -99,6 +99,10 @@ export const metadata: Metadata = {
9999
},
100100
};
101101

102+
export const viewport: Viewport = {
103+
themeColor: "#050505",
104+
};
105+
102106
export default function RootLayout({
103107
children,
104108
}: {
@@ -114,11 +118,11 @@ export default function RootLayout({
114118
<>
115119
<Script
116120
src={`https://www.googletagmanager.com/gtag/js?id=${GA_TRACKING_ID}`}
117-
strategy="afterInteractive"
121+
strategy="lazyOnload"
118122
/>
119123
<Script
120124
id="google-analytics"
121-
strategy="afterInteractive"
125+
strategy="lazyOnload"
122126
dangerouslySetInnerHTML={{
123127
__html: `
124128
window.dataLayer = window.dataLayer || [];
@@ -135,6 +139,24 @@ export default function RootLayout({
135139
/>
136140
</>
137141
)}
142+
{/* Service Worker Registration */}
143+
<Script
144+
id="register-sw"
145+
strategy="afterInteractive"
146+
dangerouslySetInnerHTML={{
147+
__html: `
148+
if ('serviceWorker' in navigator) {
149+
window.addEventListener('load', function() {
150+
navigator.serviceWorker.register('/sw.js').then(function(reg) {
151+
console.log('SW registered:', reg.scope);
152+
}).catch(function(err) {
153+
console.warn('SW registration failed:', err);
154+
});
155+
});
156+
}
157+
`
158+
}}
159+
/>
138160
</head>
139161
<body suppressHydrationWarning>
140162
<JsonLd data={[buildWebsiteSchema(), buildOrganizationSchema()]} />

app/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ type Article = {
6363
publish: boolean;
6464
};
6565

66-
export const dynamic = "force-dynamic";
66+
export const revalidate = 300;
6767

6868
type AuthorType = {
6969
id: string;

app/posts/[title]/page.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,14 @@ type RouteParams = {
2121
title: string;
2222
};
2323

24-
export const dynamic = "force-dynamic";
24+
export const revalidate = 300;
25+
26+
export async function generateStaticParams() {
27+
const articles = await getPublishedArticles();
28+
return articles.map((article) => ({
29+
title: article.slug,
30+
}));
31+
}
2532

2633
function buildKeywords(
2734
articleTitle: string,

app/posts/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export const metadata: Metadata = {
4545
},
4646
};
4747

48-
export const dynamic = "force-dynamic";
48+
export const revalidate = 300;
4949

5050
interface Article {
5151
id: string;

app/team/[author]/page.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import JsonLd from "@/components/JsonLd";
55
import PostNavigation from "@/components/PostNavigation";
66
import SocialSharing from "@/components/SocialSharing";
77
import {
8+
getAllAuthors,
89
getAuthorBySlug,
910
getPublishedArticles,
1011
getPublishedArticlesForAuthor,
@@ -34,7 +35,14 @@ type RouteParams = {
3435
author: string;
3536
};
3637

37-
export const dynamic = "force-dynamic";
38+
export const revalidate = 300;
39+
40+
export async function generateStaticParams() {
41+
const authors = await getAllAuthors();
42+
return authors.map((author) => ({
43+
author: author.slug,
44+
}));
45+
}
3846

3947
function buildAuthorSummary(name: string, job: string, city: string) {
4048
const role = job || "team member";

app/team/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export const metadata: Metadata = {
4545
},
4646
};
4747

48-
export const dynamic = "force-dynamic";
48+
export const revalidate = 300;
4949

5050
type AuthorType = {
5151
uid: string;

app/topics/[topic]/page.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import JsonLd from "@/components/JsonLd";
77
import PageTitle from "@/components/PageTitle";
88
import {
99
type ArticleRecord,
10+
buildTopicSummaries,
11+
getPublishedArticles,
1012
getPublishedTopicBySlug,
1113
type TopicSummary,
1214
} from "@/lib/content";
@@ -24,7 +26,15 @@ type RouteParams = {
2426
topic: string;
2527
};
2628

27-
export const dynamic = "force-dynamic";
29+
export const revalidate = 300;
30+
31+
export async function generateStaticParams() {
32+
const articles = await getPublishedArticles();
33+
const topics = buildTopicSummaries(articles);
34+
return topics.map((topic) => ({
35+
topic: topic.slug,
36+
}));
37+
}
2838

2939
function buildTopicDescription(label: string) {
3040
return `Browse all ${label} tutorials, guides, and docs on ${SITE_NAME}.`;

public/sw.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
const CACHE_NAME = 'lap-docs-cache-v1';
2+
const ASSETS = [
3+
'/',
4+
'/icons/favicon-32x32.png',
5+
'/icons/favicon-16x16.png',
6+
'/icons/android-chrome-192x192.png',
7+
'/icons/android-chrome-512x512.png',
8+
];
9+
10+
self.addEventListener('install', (event) => {
11+
event.waitUntil(
12+
caches.open(CACHE_NAME).then((cache) => {
13+
return cache.addAll(ASSETS).catch((err) => {
14+
console.warn('Error pre-caching assets:', err);
15+
});
16+
})
17+
);
18+
self.skipWaiting();
19+
});
20+
21+
self.addEventListener('activate', (event) => {
22+
event.waitUntil(
23+
caches.keys().then((keys) => {
24+
return Promise.all(
25+
keys.map((key) => {
26+
if (key !== CACHE_NAME) {
27+
return caches.delete(key);
28+
}
29+
})
30+
);
31+
})
32+
);
33+
self.clients.claim();
34+
});
35+
36+
self.addEventListener('fetch', (event) => {
37+
if (event.request.method !== 'GET') return;
38+
39+
const url = new URL(event.request.url);
40+
if (url.origin !== self.location.origin) return;
41+
42+
event.respondWith(
43+
caches.match(event.request).then((cachedResponse) => {
44+
if (cachedResponse) {
45+
return cachedResponse;
46+
}
47+
48+
return fetch(event.request).then((response) => {
49+
if (!response || response.status !== 200 || response.type !== 'basic') {
50+
return response;
51+
}
52+
53+
const responseToCache = response.clone();
54+
caches.open(CACHE_NAME).then((cache) => {
55+
if (!url.pathname.startsWith('/api/') && !url.pathname.startsWith('/_next/')) {
56+
cache.put(event.request, responseToCache);
57+
}
58+
});
59+
60+
return response;
61+
}).catch(() => {
62+
return caches.match('/');
63+
});
64+
})
65+
);
66+
});

0 commit comments

Comments
 (0)