@zeropress/build-core 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -3
- package/src/api/build-site.js +185 -38
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zeropress/build-core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "Shared ZeroPress build and partial-render core",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"node": ">=18.18.0"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@zeropress/preview-data-validator": "^0.3.
|
|
37
|
-
"@zeropress/theme-validator": "^0.2.
|
|
36
|
+
"@zeropress/preview-data-validator": "^0.3.3",
|
|
37
|
+
"@zeropress/theme-validator": "^0.2.4"
|
|
38
38
|
}
|
|
39
39
|
}
|
package/src/api/build-site.js
CHANGED
|
@@ -194,7 +194,12 @@ async function renderRoute(state, templateName, route) {
|
|
|
194
194
|
templateName,
|
|
195
195
|
{
|
|
196
196
|
...route,
|
|
197
|
-
meta: buildPageMeta(state.previewData.site
|
|
197
|
+
meta: buildPageMeta(state.previewData.site, {
|
|
198
|
+
currentUrl,
|
|
199
|
+
title: state.previewData.site.title,
|
|
200
|
+
description: state.previewData.site.description,
|
|
201
|
+
ogType: 'website',
|
|
202
|
+
}),
|
|
198
203
|
},
|
|
199
204
|
createRenderContext(state.previewData.site, currentUrl),
|
|
200
205
|
);
|
|
@@ -209,7 +214,15 @@ async function renderPost(state, post) {
|
|
|
209
214
|
'post',
|
|
210
215
|
{
|
|
211
216
|
post,
|
|
212
|
-
meta: buildPageMeta(state.previewData.site,
|
|
217
|
+
meta: buildPageMeta(state.previewData.site, {
|
|
218
|
+
currentUrl,
|
|
219
|
+
title: buildDocumentTitle(post.title, state.previewData.site.title),
|
|
220
|
+
description: post.excerpt,
|
|
221
|
+
ogType: 'article',
|
|
222
|
+
image: post.featured_image,
|
|
223
|
+
publishedTime: post.published_at_iso,
|
|
224
|
+
modifiedTime: post.updated_at_iso,
|
|
225
|
+
}),
|
|
213
226
|
},
|
|
214
227
|
createRenderContext(state.previewData.site, currentUrl),
|
|
215
228
|
);
|
|
@@ -229,19 +242,27 @@ async function renderPost(state, post) {
|
|
|
229
242
|
}
|
|
230
243
|
|
|
231
244
|
async function renderPage(state, page) {
|
|
245
|
+
const currentUrl = `/${encodeSlugSegment(page.slug)}/`;
|
|
232
246
|
let html = await state.engine.render(
|
|
233
247
|
'page',
|
|
234
248
|
{
|
|
235
249
|
page,
|
|
236
|
-
meta: buildPageMeta(state.previewData.site
|
|
250
|
+
meta: buildPageMeta(state.previewData.site, {
|
|
251
|
+
currentUrl,
|
|
252
|
+
title: buildDocumentTitle(page.title, state.previewData.site.title),
|
|
253
|
+
description: page.excerpt,
|
|
254
|
+
ogType: 'website',
|
|
255
|
+
image: page.featured_image,
|
|
256
|
+
}),
|
|
237
257
|
},
|
|
238
|
-
createRenderContext(state.previewData.site,
|
|
258
|
+
createRenderContext(state.previewData.site, currentUrl),
|
|
239
259
|
);
|
|
240
260
|
html = state.assetProcessor.updateAssetReferences(html, state.assetMap);
|
|
241
261
|
await writeOutput(state.writer, state.summaries, `${encodeSlugSegment(page.slug)}/index.html`, html, 'text/html');
|
|
242
262
|
state.emitted.pages.push({
|
|
243
|
-
url:
|
|
263
|
+
url: currentUrl,
|
|
244
264
|
title: page.title,
|
|
265
|
+
description: page.excerpt,
|
|
245
266
|
status: page.status,
|
|
246
267
|
});
|
|
247
268
|
}
|
|
@@ -254,7 +275,12 @@ async function maybeRenderNotFoundPage(state) {
|
|
|
254
275
|
let html = await state.engine.render(
|
|
255
276
|
'404',
|
|
256
277
|
{
|
|
257
|
-
meta: buildPageMeta(state.previewData.site
|
|
278
|
+
meta: buildPageMeta(state.previewData.site, {
|
|
279
|
+
currentUrl: '/404.html',
|
|
280
|
+
title: state.previewData.site.title,
|
|
281
|
+
description: state.previewData.site.description,
|
|
282
|
+
ogType: 'website',
|
|
283
|
+
}),
|
|
258
284
|
},
|
|
259
285
|
createRenderContext(state.previewData.site, '/404.html'),
|
|
260
286
|
);
|
|
@@ -280,23 +306,35 @@ function validateSelection(selection) {
|
|
|
280
306
|
}
|
|
281
307
|
|
|
282
308
|
function normalizePreviewData(previewData) {
|
|
309
|
+
const normalizedSite = {
|
|
310
|
+
...previewData.site,
|
|
311
|
+
mediaBaseUrl: normalizeOptionalString(previewData.site.mediaBaseUrl),
|
|
312
|
+
postsPerPage: Number.isInteger(previewData.site.postsPerPage) && previewData.site.postsPerPage > 0
|
|
313
|
+
? previewData.site.postsPerPage
|
|
314
|
+
: DEFAULT_POSTS_PER_PAGE,
|
|
315
|
+
dateFormat: normalizeNonEmptyString(previewData.site.dateFormat, DEFAULT_DATE_FORMAT),
|
|
316
|
+
timeFormat: typeof previewData.site.timeFormat === 'string' ? previewData.site.timeFormat : DEFAULT_TIME_FORMAT,
|
|
317
|
+
timezone: normalizeNonEmptyString(previewData.site.timezone, DEFAULT_TIMEZONE),
|
|
318
|
+
locale: normalizeLocale(previewData.site.locale || DEFAULT_LOCALE),
|
|
319
|
+
disallowComments: previewData.site.disallowComments === true,
|
|
320
|
+
};
|
|
321
|
+
|
|
283
322
|
return {
|
|
284
323
|
...previewData,
|
|
285
|
-
site:
|
|
286
|
-
...previewData.site,
|
|
287
|
-
postsPerPage: Number.isInteger(previewData.site.postsPerPage) && previewData.site.postsPerPage > 0
|
|
288
|
-
? previewData.site.postsPerPage
|
|
289
|
-
: DEFAULT_POSTS_PER_PAGE,
|
|
290
|
-
dateFormat: normalizeNonEmptyString(previewData.site.dateFormat, DEFAULT_DATE_FORMAT),
|
|
291
|
-
timeFormat: typeof previewData.site.timeFormat === 'string' ? previewData.site.timeFormat : DEFAULT_TIME_FORMAT,
|
|
292
|
-
timezone: normalizeNonEmptyString(previewData.site.timezone, DEFAULT_TIMEZONE),
|
|
293
|
-
locale: normalizeLocale(previewData.site.locale || DEFAULT_LOCALE),
|
|
294
|
-
disallowComments: previewData.site.disallowComments === true,
|
|
295
|
-
},
|
|
324
|
+
site: normalizedSite,
|
|
296
325
|
content: {
|
|
297
326
|
...previewData.content,
|
|
298
|
-
posts:
|
|
299
|
-
|
|
327
|
+
posts: previewData.content.posts
|
|
328
|
+
.map((post) => ({
|
|
329
|
+
...post,
|
|
330
|
+
author_avatar: normalizeMediaField(post.author_avatar, normalizedSite.mediaBaseUrl),
|
|
331
|
+
featured_image: normalizeMediaField(post.featured_image, normalizedSite.mediaBaseUrl),
|
|
332
|
+
}))
|
|
333
|
+
.sort((left, right) => toDate(right.published_at_iso).getTime() - toDate(left.published_at_iso).getTime()),
|
|
334
|
+
pages: previewData.content.pages.map((page) => ({
|
|
335
|
+
...page,
|
|
336
|
+
featured_image: normalizeMediaField(page.featured_image, normalizedSite.mediaBaseUrl),
|
|
337
|
+
})),
|
|
300
338
|
categories: [...previewData.content.categories],
|
|
301
339
|
tags: [...previewData.content.tags],
|
|
302
340
|
},
|
|
@@ -708,6 +746,10 @@ function normalizeNonEmptyString(value, fallback) {
|
|
|
708
746
|
return typeof value === 'string' && value.trim() ? value : fallback;
|
|
709
747
|
}
|
|
710
748
|
|
|
749
|
+
function normalizeOptionalString(value) {
|
|
750
|
+
return typeof value === 'string' && value.trim() ? value.trim() : '';
|
|
751
|
+
}
|
|
752
|
+
|
|
711
753
|
function normalizeLocale(value) {
|
|
712
754
|
if (typeof value !== 'string' || !value.trim()) {
|
|
713
755
|
return DEFAULT_LOCALE;
|
|
@@ -831,13 +873,129 @@ function createRenderContext(site, currentUrl) {
|
|
|
831
873
|
};
|
|
832
874
|
}
|
|
833
875
|
|
|
834
|
-
function buildPageMeta(site,
|
|
835
|
-
const
|
|
876
|
+
function buildPageMeta(site, options = {}) {
|
|
877
|
+
const resolvedTitle = normalizeNonEmptyString(options.title, site.title);
|
|
878
|
+
const resolvedDescription = normalizeOptionalString(options.description);
|
|
879
|
+
const canonicalUrl = resolveMetaCanonicalUrl(site, options.currentUrl);
|
|
880
|
+
const ogImage = resolveMetaImageUrl(options.image);
|
|
881
|
+
const ogType = normalizeNonEmptyString(options.ogType, 'website');
|
|
882
|
+
const publishedTime = normalizeOptionalString(options.publishedTime);
|
|
883
|
+
const modifiedTime = normalizeOptionalString(options.modifiedTime);
|
|
884
|
+
|
|
885
|
+
const meta = {
|
|
886
|
+
title: escapeHtml(resolvedTitle),
|
|
887
|
+
description: resolvedDescription ? escapeHtml(resolvedDescription) : '',
|
|
888
|
+
canonical_url: canonicalUrl ? escapeHtml(canonicalUrl) : '',
|
|
889
|
+
og_title: escapeHtml(resolvedTitle),
|
|
890
|
+
og_description: resolvedDescription ? escapeHtml(resolvedDescription) : '',
|
|
891
|
+
og_type: escapeHtml(ogType),
|
|
892
|
+
og_url: canonicalUrl ? escapeHtml(canonicalUrl) : '',
|
|
893
|
+
og_site_name: escapeHtml(site.title),
|
|
894
|
+
og_image: ogImage ? escapeHtml(ogImage) : '',
|
|
895
|
+
article_published_time: publishedTime ? escapeHtml(publishedTime) : '',
|
|
896
|
+
article_modified_time: modifiedTime ? escapeHtml(modifiedTime) : '',
|
|
897
|
+
};
|
|
898
|
+
|
|
836
899
|
return {
|
|
837
|
-
|
|
900
|
+
...meta,
|
|
901
|
+
head_tags: buildMetaHeadTags(meta),
|
|
838
902
|
};
|
|
839
903
|
}
|
|
840
904
|
|
|
905
|
+
function buildDocumentTitle(contentTitle, siteTitle) {
|
|
906
|
+
const resolvedContentTitle = normalizeNonEmptyString(contentTitle, siteTitle);
|
|
907
|
+
const resolvedSiteTitle = normalizeNonEmptyString(siteTitle, resolvedContentTitle);
|
|
908
|
+
return `${resolvedContentTitle} - ${resolvedSiteTitle}`;
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
function buildMetaHeadTags(meta) {
|
|
912
|
+
const tags = [];
|
|
913
|
+
|
|
914
|
+
if (meta.description) {
|
|
915
|
+
tags.push(`<meta name="description" content="${meta.description}">`);
|
|
916
|
+
}
|
|
917
|
+
if (meta.canonical_url) {
|
|
918
|
+
tags.push(`<link rel="canonical" href="${meta.canonical_url}">`);
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
tags.push(`<meta property="og:title" content="${meta.og_title}">`);
|
|
922
|
+
if (meta.og_description) {
|
|
923
|
+
tags.push(`<meta property="og:description" content="${meta.og_description}">`);
|
|
924
|
+
}
|
|
925
|
+
tags.push(`<meta property="og:type" content="${meta.og_type}">`);
|
|
926
|
+
if (meta.og_url) {
|
|
927
|
+
tags.push(`<meta property="og:url" content="${meta.og_url}">`);
|
|
928
|
+
}
|
|
929
|
+
tags.push(`<meta property="og:site_name" content="${meta.og_site_name}">`);
|
|
930
|
+
if (meta.og_image) {
|
|
931
|
+
tags.push(`<meta property="og:image" content="${meta.og_image}">`);
|
|
932
|
+
}
|
|
933
|
+
if (meta.article_published_time) {
|
|
934
|
+
tags.push(`<meta property="article:published_time" content="${meta.article_published_time}">`);
|
|
935
|
+
}
|
|
936
|
+
if (meta.article_modified_time) {
|
|
937
|
+
tags.push(`<meta property="article:modified_time" content="${meta.article_modified_time}">`);
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
return tags.length ? `${tags.join('\n')}\n` : '';
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
function resolveMetaCanonicalUrl(site, currentUrl) {
|
|
944
|
+
if (!hasCanonicalSiteUrl(site.url) || !normalizeOptionalString(currentUrl)) {
|
|
945
|
+
return '';
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
return resolveSiteUrl(site.url, currentUrl);
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
function resolveMetaImageUrl(image) {
|
|
952
|
+
const normalizedImage = normalizeOptionalString(image);
|
|
953
|
+
if (!normalizedImage) {
|
|
954
|
+
return '';
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
if (isAbsoluteUrl(normalizedImage)) {
|
|
958
|
+
return normalizedImage;
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
return '';
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
function normalizeMediaField(value, mediaBaseUrl) {
|
|
965
|
+
if (value === undefined) {
|
|
966
|
+
return undefined;
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
const normalizedValue = normalizeOptionalString(value);
|
|
970
|
+
if (!normalizedValue) {
|
|
971
|
+
return '';
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
if (isAbsoluteUrl(normalizedValue)) {
|
|
975
|
+
return normalizedValue;
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
const normalizedBaseUrl = normalizeOptionalString(mediaBaseUrl);
|
|
979
|
+
if (!normalizedBaseUrl) {
|
|
980
|
+
return '';
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
try {
|
|
984
|
+
return decodeURI(new URL(normalizedValue, normalizedBaseUrl).toString());
|
|
985
|
+
} catch {
|
|
986
|
+
return '';
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
function isAbsoluteUrl(value) {
|
|
991
|
+
try {
|
|
992
|
+
new URL(value);
|
|
993
|
+
return true;
|
|
994
|
+
} catch {
|
|
995
|
+
return false;
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
|
|
841
999
|
async function writeOutput(writer, summaries, path, content, contentType) {
|
|
842
1000
|
const normalizedPath = normalizeOutputPath(path);
|
|
843
1001
|
await writer.write({ path: normalizedPath, content, contentType });
|
|
@@ -889,7 +1047,6 @@ function buildSitemapXml(site, emitted, generatedAt) {
|
|
|
889
1047
|
.filter((route) => route.url === '/')
|
|
890
1048
|
.map((route) => ({
|
|
891
1049
|
url: route.url,
|
|
892
|
-
lastmod: generatedAt,
|
|
893
1050
|
changefreq: 'daily',
|
|
894
1051
|
priority: 1.0,
|
|
895
1052
|
})),
|
|
@@ -901,28 +1058,17 @@ function buildSitemapXml(site, emitted, generatedAt) {
|
|
|
901
1058
|
})),
|
|
902
1059
|
...emitted.pages.map((page) => ({
|
|
903
1060
|
url: page.url,
|
|
904
|
-
lastmod: generatedAt,
|
|
905
1061
|
changefreq: 'monthly',
|
|
906
1062
|
priority: 0.7,
|
|
907
1063
|
})),
|
|
908
|
-
...emitted.categoryRoutes.filter((route) => route.page === 1).map((route) => ({
|
|
909
|
-
url: route.url,
|
|
910
|
-
lastmod: generatedAt,
|
|
911
|
-
changefreq: 'weekly',
|
|
912
|
-
priority: 0.6,
|
|
913
|
-
})),
|
|
914
|
-
...emitted.tagRoutes.filter((route) => route.page === 1).map((route) => ({
|
|
915
|
-
url: route.url,
|
|
916
|
-
lastmod: generatedAt,
|
|
917
|
-
changefreq: 'weekly',
|
|
918
|
-
priority: 0.5,
|
|
919
|
-
})),
|
|
920
1064
|
];
|
|
921
1065
|
|
|
922
1066
|
const body = entries.map((entry) => {
|
|
923
1067
|
const loc = escapeXml(resolveSiteUrl(site.url, entry.url));
|
|
924
|
-
const lastmod = entry.lastmod
|
|
925
|
-
|
|
1068
|
+
const lastmod = entry.lastmod
|
|
1069
|
+
? `\n <lastmod>${entry.lastmod.toISOString()}</lastmod>`
|
|
1070
|
+
: '';
|
|
1071
|
+
return ` <url>\n <loc>${loc}</loc>${lastmod}\n <changefreq>${entry.changefreq}</changefreq>\n <priority>${entry.priority.toFixed(1)}</priority>\n </url>`;
|
|
926
1072
|
}).join('\n');
|
|
927
1073
|
|
|
928
1074
|
return `<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n${body}\n</urlset>`;
|
|
@@ -965,6 +1111,7 @@ function buildMetaJson(site, emitted, generatedAt) {
|
|
|
965
1111
|
...emitted.pages.map((page) => ({
|
|
966
1112
|
url: page.url,
|
|
967
1113
|
title: page.title,
|
|
1114
|
+
description: page.description,
|
|
968
1115
|
type: 'page',
|
|
969
1116
|
metadata: { status: page.status },
|
|
970
1117
|
})),
|