Skip to content

Commit c384707

Browse files
authored
fix: add current-date resource handler to CLI templates (#5439)
## Problem The current-date system resource works in the Webstudio builder but fails in published sites with "dateTime attribute is not set" errors. ## Root Cause The CLI templates' `customFetch` functions handle the `sitemap.xml` local resource but don't handle the `current-date` resource, causing fetch requests to fail when sites are published. ## Solution Added `current-date` handler to all CLI template `customFetch` functions, following the same pattern as the existing `sitemap.xml` handler. ## Changes - Add current-date handler to Remix HTML/XML templates - Add current-date handler to React Router HTML/XML templates - Add customFetch with current-date handler to SSG template - Normalize dates to midnight UTC to prevent hydration mismatches ## Testing The fix ensures that when the Time component uses `system.currentDate`, it will work correctly in published sites, not just in the builder.
1 parent 1f2e7a2 commit c384707

File tree

5 files changed

+103
-2
lines changed

5 files changed

+103
-2
lines changed

packages/cli/templates/defaults/app/route-templates/html.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,24 @@ const customFetch: typeof fetch = (input, init) => {
5454
return Promise.resolve(response);
5555
}
5656

57+
if (isLocalResource(input, "current-date")) {
58+
const now = new Date();
59+
// Normalize to midnight UTC to prevent hydration mismatches
60+
const startOfDay = new Date(
61+
Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate())
62+
);
63+
const data = {
64+
iso: startOfDay.toISOString(),
65+
year: startOfDay.getUTCFullYear(),
66+
month: startOfDay.getUTCMonth() + 1, // 1-12 instead of 0-11
67+
day: startOfDay.getUTCDate(),
68+
timestamp: startOfDay.getTime(),
69+
};
70+
const response = new Response(JSON.stringify(data));
71+
response.headers.set("content-type", "application/json; charset=utf-8");
72+
return Promise.resolve(response);
73+
}
74+
5775
return cachedFetch(projectId, input, init);
5876
};
5977

packages/cli/templates/defaults/app/route-templates/xml.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,24 @@ const customFetch: typeof fetch = (input, init) => {
2222
return Promise.resolve(response);
2323
}
2424

25+
if (isLocalResource(input, "current-date")) {
26+
const now = new Date();
27+
// Normalize to midnight UTC to prevent hydration mismatches
28+
const startOfDay = new Date(
29+
Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate())
30+
);
31+
const data = {
32+
iso: startOfDay.toISOString(),
33+
year: startOfDay.getUTCFullYear(),
34+
month: startOfDay.getUTCMonth() + 1, // 1-12 instead of 0-11
35+
day: startOfDay.getUTCDate(),
36+
timestamp: startOfDay.getTime(),
37+
};
38+
const response = new Response(JSON.stringify(data));
39+
response.headers.set("content-type", "application/json; charset=utf-8");
40+
return Promise.resolve(response);
41+
}
42+
2543
return fetch(input, init);
2644
};
2745

packages/cli/templates/react-router/app/route-templates/html.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,24 @@ const customFetch: typeof fetch = (input, init) => {
5353
return Promise.resolve(response);
5454
}
5555

56+
if (isLocalResource(input, "current-date")) {
57+
const now = new Date();
58+
// Normalize to midnight UTC to prevent hydration mismatches
59+
const startOfDay = new Date(
60+
Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate())
61+
);
62+
const data = {
63+
iso: startOfDay.toISOString(),
64+
year: startOfDay.getUTCFullYear(),
65+
month: startOfDay.getUTCMonth() + 1, // 1-12 instead of 0-11
66+
day: startOfDay.getUTCDate(),
67+
timestamp: startOfDay.getTime(),
68+
};
69+
const response = new Response(JSON.stringify(data));
70+
response.headers.set("content-type", "application/json; charset=utf-8");
71+
return Promise.resolve(response);
72+
}
73+
5674
return cachedFetch(projectId, input, init);
5775
};
5876

packages/cli/templates/react-router/app/route-templates/xml.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,24 @@ const customFetch: typeof fetch = (input, init) => {
2222
return Promise.resolve(response);
2323
}
2424

25+
if (isLocalResource(input, "current-date")) {
26+
const now = new Date();
27+
// Normalize to midnight UTC to prevent hydration mismatches
28+
const startOfDay = new Date(
29+
Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate())
30+
);
31+
const data = {
32+
iso: startOfDay.toISOString(),
33+
year: startOfDay.getUTCFullYear(),
34+
month: startOfDay.getUTCMonth() + 1, // 1-12 instead of 0-11
35+
day: startOfDay.getUTCDate(),
36+
timestamp: startOfDay.getTime(),
37+
};
38+
const response = new Response(JSON.stringify(data));
39+
response.headers.set("content-type", "application/json; charset=utf-8");
40+
return Promise.resolve(response);
41+
}
42+
2543
return fetch(input, init);
2644
};
2745

packages/cli/templates/ssg/app/route-templates/html/+data.ts

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,34 @@
11
import type { PageContextServer } from "vike/types";
22
import { redirect } from "vike/abort";
3-
import { loadResources } from "@webstudio-is/sdk/runtime";
3+
import { isLocalResource, loadResources } from "@webstudio-is/sdk/runtime";
44
import { getPageMeta, getResources } from "__SERVER__";
55

6+
const customFetch: typeof fetch = (input, init) => {
7+
if (typeof input !== "string") {
8+
return fetch(input, init);
9+
}
10+
11+
if (isLocalResource(input, "current-date")) {
12+
const now = new Date();
13+
// Normalize to midnight UTC to prevent hydration mismatches
14+
const startOfDay = new Date(
15+
Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate())
16+
);
17+
const data = {
18+
iso: startOfDay.toISOString(),
19+
year: startOfDay.getUTCFullYear(),
20+
month: startOfDay.getUTCMonth() + 1, // 1-12 instead of 0-11
21+
day: startOfDay.getUTCDate(),
22+
timestamp: startOfDay.getTime(),
23+
};
24+
const response = new Response(JSON.stringify(data));
25+
response.headers.set("content-type", "application/json; charset=utf-8");
26+
return Promise.resolve(response);
27+
}
28+
29+
return fetch(input, init);
30+
};
31+
632
export const data = async (pageContext: PageContextServer) => {
733
const url = new URL(pageContext.urlOriginal, "http://url");
834
const headers = new Headers(pageContext.headers ?? {});
@@ -18,7 +44,10 @@ export const data = async (pageContext: PageContextServer) => {
1844
pathname: url.pathname,
1945
};
2046

21-
const resources = await loadResources(fetch, getResources({ system }).data);
47+
const resources = await loadResources(
48+
customFetch,
49+
getResources({ system }).data
50+
);
2251
const pageMeta = getPageMeta({ system, resources });
2352

2453
if (pageMeta.redirect) {

0 commit comments

Comments
 (0)