Architecture

Static pages, interactive details

Sahil Reghate ·

This portfolio uses a small build step rather than making every visitor wait for JavaScript to create the page. The same page renderer supplies the generated HTML and the browser fallback.

Start with the first response

The interesting content on this site is the work, the services and the explanation behind them. It should already be present when someone opens a page. Interactive details can then improve the experience without becoming the only way to read it.

The build imports renderApp from the shared templates module. For each route, it replaces the app slot with the rendered page content and writes that HTML into dist. The browser uses the renderer only as a fallback when the app container is empty.

Keep the content in one renderer

The important part is the shared function, not the amount of build tooling. A content change in a project or a service flows into the generated page when the build runs. There is no second handwritten version of the page to keep in sync.

JavaScript excerpt from build.mjs
const out = withMetadata.replace(slot, () =>
  `<div id="app">${renderApp(page)}</div><!--/app-->`
).replace(/[ \t]+$/gm, '');
await writeFile(file, out);

The app-slot comment marks the end of the replaceable content. That makes the next build replace the existing rendered page instead of appending another copy.

Give each route its own identity

Metadata lives in dist/metadata.js. Each page has a path, title and description; the generator adds its canonical URL, social previews and structured data. The work page derives its project count from the project array.

The build replaces managed metadata while retaining unrelated head elements, including verification tags. A content edit can therefore update the page description without silently discarding a separately added ownership-verification tag.

The canonical URLs and sitemap use the same public domain and trailing-slash convention. That consistency is an implementation choice. It is not a promise that a search engine will index or rank a page.

Check a few failures before shipping

The existing build checks for one real page heading, image alternative text, parseable JSON-LD, local link targets and social-preview assets. These are narrow checks for mistakes that would make a page harder to use or share.

They do not replace looking at the page. Layout, keyboard access, image loading and the final response on the deployed host still need separate verification.

  • Open a route with JavaScript disabled and check that useful content remains.
  • Inspect the HTML response for the expected title and canonical URL.
  • Follow internal links and verify the final deployed response, including the 404 page.