From 367fe43277fb390143cd2421dd7c6e08a1a18ceb Mon Sep 17 00:00:00 2001 From: Tom Herni Date: Thu, 2 Jul 2026 21:52:05 +0200 Subject: [PATCH] wip: refactor setup for rendering pages --- src/build.ts | 12 +- .../feeds/create-atom-feed.ts | 0 .../feeds/create-rss-feed.ts | 0 .../feeds/create-sitemap.ts | 18 +-- src/{generator/optimize => build}/optimize.ts | 6 +- .../posts/get-metadata.ts | 0 src/{generator => build}/posts/get-posts.ts | 0 .../posts/parse-markdown.ts | 0 .../render-pages => build}/render-pages.ts | 56 ++++--- .../social-image/create-social-image.ts | 0 .../social-image/resources/picture.png | Bin .../resources/source-sans-3-bold.ttf | Bin src/constants.ts | 1 - src/generator/render-pages/render-page.ts | 38 ----- src/includes/site-header.ts | 14 +- src/layouts/base.ts | 27 ++-- src/layouts/post.ts | 153 +++++++++--------- src/layouts/tag.ts | 31 ++-- src/static/assets/css/styles.css | 2 +- src/static/blog/index.ts | 22 +-- src/static/index.ts | 30 ++-- src/static/page-not-found/index.ts | 30 ++-- src/static/tags/index.ts | 22 +-- src/types.ts | 84 +++------- 24 files changed, 240 insertions(+), 306 deletions(-) rename src/{generator => build}/feeds/create-atom-feed.ts (100%) rename src/{generator => build}/feeds/create-rss-feed.ts (100%) rename src/{generator => build}/feeds/create-sitemap.ts (66%) rename src/{generator/optimize => build}/optimize.ts (97%) rename src/{generator => build}/posts/get-metadata.ts (100%) rename src/{generator => build}/posts/get-posts.ts (100%) rename src/{generator => build}/posts/parse-markdown.ts (100%) rename src/{generator/render-pages => build}/render-pages.ts (57%) rename src/{generator => build}/social-image/create-social-image.ts (100%) rename src/{generator => build}/social-image/resources/picture.png (100%) rename src/{generator => build}/social-image/resources/source-sans-3-bold.ttf (100%) delete mode 100644 src/generator/render-pages/render-page.ts diff --git a/src/build.ts b/src/build.ts index bf9d400..85eb588 100644 --- a/src/build.ts +++ b/src/build.ts @@ -1,10 +1,10 @@ import fs from 'node:fs'; -import { createAtomFeed } from './generator/feeds/create-atom-feed'; -import { createRssFeed } from './generator/feeds/create-rss-feed'; -import { createSitemap } from './generator/feeds/create-sitemap'; -import { optimize } from './generator/optimize/optimize'; -import { getPosts } from './generator/posts/get-posts'; -import { renderPages } from './generator/render-pages/render-pages'; +import { createAtomFeed } from './build/feeds/create-atom-feed'; +import { createRssFeed } from './build/feeds/create-rss-feed'; +import { createSitemap } from './build/feeds/create-sitemap'; +import { optimize } from './build/optimize'; +import { getPosts } from './build/posts/get-posts'; +import { renderPages } from './build/render-pages'; import { copySourceToTarget } from './utils/node'; import { DIR_DIST, DIR_SRC_STATIC } from './constants'; diff --git a/src/generator/feeds/create-atom-feed.ts b/src/build/feeds/create-atom-feed.ts similarity index 100% rename from src/generator/feeds/create-atom-feed.ts rename to src/build/feeds/create-atom-feed.ts diff --git a/src/generator/feeds/create-rss-feed.ts b/src/build/feeds/create-rss-feed.ts similarity index 100% rename from src/generator/feeds/create-rss-feed.ts rename to src/build/feeds/create-rss-feed.ts diff --git a/src/generator/feeds/create-sitemap.ts b/src/build/feeds/create-sitemap.ts similarity index 66% rename from src/generator/feeds/create-sitemap.ts rename to src/build/feeds/create-sitemap.ts index 676c646..906661e 100644 --- a/src/generator/feeds/create-sitemap.ts +++ b/src/build/feeds/create-sitemap.ts @@ -1,4 +1,4 @@ -import type { ImportedPageData, RenderedPages } from '@types'; +import type { PageData, RenderedPages } from '@types'; import path from 'node:path'; import { formatDateIso } from '../../utils/date'; import { html, map } from '../../utils/html'; @@ -6,16 +6,16 @@ import { createFile } from '../../utils/node'; import { BUILD } from '../../config'; import { DIR_DIST } from '../../constants'; -function pagesToSitemapEntries(pages: ImportedPageData[]): string { - return map(pages, ({ url, config }) => { - const date = config?.updated || config?.date || BUILD.date; - return html` +function pagesToSitemapEntries(pages: PageData[]): string { + return map( + pages, + ({ url, updated, date }) => html` ${url} - ${formatDateIso(date)} + ${formatDateIso(updated || date || BUILD.date)} - `; - }); + `, + ); } export function createSitemap(pages: RenderedPages): void { @@ -25,7 +25,7 @@ export function createSitemap(pages: RenderedPages): void { const contents = html` ${pagesToSitemapEntries([ - ...content.filter((page) => !page.config.excludeFromSitemap), + ...content.filter((page) => !page.excludeFromSitemap), ...posts, ...tags, ])} diff --git a/src/generator/optimize/optimize.ts b/src/build/optimize.ts similarity index 97% rename from src/generator/optimize/optimize.ts rename to src/build/optimize.ts index 6129224..36015b1 100644 --- a/src/generator/optimize/optimize.ts +++ b/src/build/optimize.ts @@ -2,10 +2,10 @@ import { transform } from 'lightningcss'; import crypto from 'node:crypto'; import fs from 'node:fs'; import path from 'node:path'; -import { minify as minifyJs } from 'terser'; import { minify as minifyHtml } from 'html-minifier-terser'; -import { findFilesByExtension } from '../../utils/node'; -import { DIR_DIST } from '../../constants'; +import { minify as minifyJs } from 'terser'; +import { findFilesByExtension } from '../utils/node'; +import { DIR_DIST } from '../constants'; // A map of asset file paths to their hashed file names. const fileHashMap: Record = {}; diff --git a/src/generator/posts/get-metadata.ts b/src/build/posts/get-metadata.ts similarity index 100% rename from src/generator/posts/get-metadata.ts rename to src/build/posts/get-metadata.ts diff --git a/src/generator/posts/get-posts.ts b/src/build/posts/get-posts.ts similarity index 100% rename from src/generator/posts/get-posts.ts rename to src/build/posts/get-posts.ts diff --git a/src/generator/posts/parse-markdown.ts b/src/build/posts/parse-markdown.ts similarity index 100% rename from src/generator/posts/parse-markdown.ts rename to src/build/posts/parse-markdown.ts diff --git a/src/generator/render-pages/render-pages.ts b/src/build/render-pages.ts similarity index 57% rename from src/generator/render-pages/render-pages.ts rename to src/build/render-pages.ts index 566c3f1..90dac27 100644 --- a/src/generator/render-pages/render-pages.ts +++ b/src/build/render-pages.ts @@ -1,17 +1,11 @@ -import type { - BasePageData, - ImportedPageData, - LayoutPostData, - LayoutTagData, - Post, - RenderedPages, -} from '@types'; +import type { Layout, Page, PageData, Post, RenderedPages } from '@types'; import path from 'node:path'; -import { findFilesByExtension } from '../../utils/node'; -import { BUILD } from '../../config'; -import { DIR_DIST, DIR_SRC_STATIC } from '../../constants'; -import { createSocialImage } from '../social-image/create-social-image'; -import { getLayoutPath, renderPage } from './render-page'; +import postLayout from '../layouts/post'; +import tagLayout from '../layouts/tag'; +import { createFile, findFilesByExtension } from '../utils/node'; +import { BUILD } from '../config'; +import { DIR_DIST, DIR_SRC_STATIC } from '../constants'; +import { createSocialImage } from './social-image/create-social-image'; export async function renderPages( posts: Post[], @@ -30,20 +24,20 @@ export async function renderContentPage( file: string, posts: Post[], tags: string[], -): Promise { +): Promise { + const layout = (await import(file)).default as Page; const target = resolveSrcDirToDistDir(file).replace('.ts', '.html'); - const data: BasePageData = { url: resolveUrl(target), posts, tags }; - return renderPage(file, target, data); + const data: PageData = { url: resolveUrl(target), posts, tags }; + return renderPage(target, layout, data); } async function renderPostPage( post: Post, posts: Post[], tags: string[], -): Promise { - const layout = getLayoutPath('post'); +): Promise { const target = resolveSrcDirToDistDir(post.file).replace('.md', '.html'); - const data: LayoutPostData = { + const data: PageData = { url: resolveUrl(target), posts, tags, @@ -52,7 +46,7 @@ async function renderPostPage( }; const [page] = await Promise.all([ - renderPage(layout, target, data), + renderPage(target, postLayout, data), createSocialImage(post, target), ]); @@ -63,18 +57,30 @@ async function renderTagPage( tag: string, posts: Post[], tags: string[], -): Promise { - const layout = getLayoutPath('tag'); +): Promise { const target = path.join(DIR_DIST, `/tags/${tag}/index.html`); - const data: LayoutTagData = { url: resolveUrl(target), posts, tags, tag }; - return renderPage(layout, target, data); + const data: PageData = { url: resolveUrl(target), posts, tags, tag }; + return renderPage(target, tagLayout, data); +} + +function renderPage( + target: string, + pageOrLayout: Page | Layout, + data: PageData, +): PageData { + const result = pageOrLayout(data); + if (!result.content) { + throw new Error('No content'); + } + createFile(target, result.content); + return result; } function resolveSrcDirToDistDir(file: string): string { return path.join(DIR_DIST, path.relative(DIR_SRC_STATIC, file)); } -export function resolveUrl(file: string): string { +function resolveUrl(file: string): string { const relativePath = path.relative(DIR_DIST, file); const relativeUrl = path.normalize(path.dirname(relativePath) + '/'); return new URL(relativeUrl, BUILD.baseUrl).href; diff --git a/src/generator/social-image/create-social-image.ts b/src/build/social-image/create-social-image.ts similarity index 100% rename from src/generator/social-image/create-social-image.ts rename to src/build/social-image/create-social-image.ts diff --git a/src/generator/social-image/resources/picture.png b/src/build/social-image/resources/picture.png similarity index 100% rename from src/generator/social-image/resources/picture.png rename to src/build/social-image/resources/picture.png diff --git a/src/generator/social-image/resources/source-sans-3-bold.ttf b/src/build/social-image/resources/source-sans-3-bold.ttf similarity index 100% rename from src/generator/social-image/resources/source-sans-3-bold.ttf rename to src/build/social-image/resources/source-sans-3-bold.ttf diff --git a/src/constants.ts b/src/constants.ts index 9ad018c..1f69fd2 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -4,7 +4,6 @@ export const BASE_URL_DEV = 'http://localhost:3000/'; export const BASE_URL_PROD = 'https://tomherni.dev/'; export const DIR_DIST = path.resolve('dist/'); -export const DIR_SRC_LAYOUTS = path.resolve('src/layouts/'); export const DIR_SRC_STATIC = path.resolve('src/static/'); export const SOCIAL_FILE_NAME = 'social.jpg'; diff --git a/src/generator/render-pages/render-page.ts b/src/generator/render-pages/render-page.ts deleted file mode 100644 index 48dfbd5..0000000 --- a/src/generator/render-pages/render-page.ts +++ /dev/null @@ -1,38 +0,0 @@ -import type { BasePageData, ImportedPageData, Page } from '@types'; -import fs from 'node:fs'; -import path from 'node:path'; -import { createFile } from '../../utils/node'; -import { DIR_SRC_LAYOUTS } from '../../constants'; - -export async function renderPage( - source: string, - target: string, - data: BasePageData | ImportedPageData, -): Promise { - const page: Page = (await import(source)).default; - const content = page.content(data); - const config = page.config?.(data); - - if (config?.layout) { - const { layout, ..._config } = config; - const layoutPath = getLayoutPath(layout); - - return renderPage(layoutPath, target, { - ...data, - config: { ...('config' in data ? data.config : {}), ..._config }, - content, - }); - } - - createFile(target, content); - return { ...data, content, config: (data as ImportedPageData).config }; -} - -export function getLayoutPath(layout: string): string { - const layoutPath = path.join(DIR_SRC_LAYOUTS, `${layout}.ts`); - - if (!fs.existsSync(layoutPath)) { - throw new Error('Layout does not exist'); - } - return layoutPath; -} diff --git a/src/includes/site-header.ts b/src/includes/site-header.ts index bffb903..e297c08 100644 --- a/src/includes/site-header.ts +++ b/src/includes/site-header.ts @@ -1,7 +1,7 @@ -import type { PageConfig } from '@types'; +import type { PageData } from '@types'; import { html } from '../utils/html'; -export const siteHeader = (config: PageConfig = {}) => html` +export const siteHeader = (data: PageData) => html`