Skip to content

Commit a8a6b61

Browse files
committed
feat(dev): add content watcher for HMR and integrate with Next.js config
1 parent fb894c2 commit a8a6b61

File tree

5 files changed

+62
-6
lines changed

5 files changed

+62
-6
lines changed

app/(website)/blog/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { SlideIn, StaggerContainer } from "@/components/ui/motion/motion-compone
66
import { getAuthors } from "@/lib/author";
77
import { getBlogPosts, getBlogTags } from "@/lib/blog";
88

9-
export const dynamic = "force-dynamic";
9+
// export const dynamic = "force-dynamic";
1010
export const revalidate = 5; // Revalidate every 5 seconds
1111

1212
export const metadata: Metadata = {

app/(website)/docs/[...slug]/page.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { ErrorBoundary } from "@/components/docs/content/error-boundary";
1313
import { ReadingTime } from "@/components/docs/content/reading-time";
1414
import { components, mdxOptions } from "@/components/ui/mdx/mdx-components";
1515
import { docsStructure } from "@/lib/sidebar-structure";
16+
import { refreshTimestamp } from "../refresh";
1617

1718
type DocMeta = {
1819
title: string;
@@ -148,6 +149,7 @@ export function generateStaticParams() {
148149
export default async function DocPage({ params }: Props) {
149150
const resolvedParams = await params;
150151
const doc = await getDocBySlug(resolvedParams.slug);
152+
void refreshTimestamp;
151153
if (!doc) {
152154
notFound();
153155
}

app/(website)/docs/refresh.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// This file is automatically updated to trigger hot reloads
2+
export const refreshTimestamp = 1765590851394;

lib/content-watcher.mjs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import fs from "node:fs";
2+
import path from "node:path";
3+
4+
const CONFIG = {
5+
debounceMs: 200,
6+
contentDir: "content",
7+
triggerFile: "app/(website)/docs/refresh.ts", // File that triggers the HMR
8+
};
9+
10+
const isMdxFile = (filename) => filename && /\.(mdx?|md)$/.test(filename);
11+
12+
const updateTriggerFile = (filePath) => {
13+
const timestamp = Date.now();
14+
const content = `// This file is automatically updated to trigger hot reloads\nexport const refreshTimestamp = ${timestamp};\n`;
15+
16+
try {
17+
fs.writeFileSync(filePath, content);
18+
} catch (error) {
19+
console.error(`[ContentWatcher] Failed to update HMR trigger: ${error.message}`);
20+
}
21+
};
22+
23+
export function setupContentWatcher() {
24+
if (process.env.NODE_ENV !== "development") {
25+
return;
26+
}
27+
28+
const cwd = process.cwd();
29+
const contentPath = path.join(cwd, CONFIG.contentDir);
30+
const triggerFilePath = path.join(cwd, CONFIG.triggerFile);
31+
32+
if (!fs.existsSync(contentPath)) {
33+
return;
34+
}
35+
36+
let debounceTimer;
37+
38+
const handleFileChange = (_eventType, filename) => {
39+
if (!isMdxFile(filename)) {
40+
return;
41+
}
42+
43+
clearTimeout(debounceTimer);
44+
debounceTimer = setTimeout(() => {
45+
updateTriggerFile(triggerFilePath);
46+
}, CONFIG.debounceMs);
47+
};
48+
49+
try {
50+
fs.watch(contentPath, { recursive: true }, handleFileChange);
51+
} catch (error) {
52+
console.warn(`[ContentWatcher] Failed to start watcher: ${error.message}`);
53+
}
54+
}

next.config.mjs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
2-
3-
4-
51
const nextConfig = {
62
pageExtensions: ["js", "jsx", "ts", "tsx"],
73
images: {
@@ -61,12 +57,14 @@ const nextConfig = {
6157
allowedOrigins: ["eternalcode.pl", "www.eternalcode.pl"],
6258
bodySizeLimit: "5mb",
6359
},
64-
6560
},
6661
bundlePagesRouterDependencies: true,
6762
serverExternalPackages: ["gray-matter", "sharp", "payload", "@payloadcms/db-sqlite"],
6863
};
6964

7065
import { withPayload } from '@payloadcms/next/withPayload'
66+
import { setupContentWatcher } from './lib/content-watcher.mjs';
67+
68+
setupContentWatcher();
7169

7270
export default withPayload(nextConfig);

0 commit comments

Comments
 (0)