2026-03-25 10:08:46 +07:00
|
|
|
/**
|
|
|
|
|
* SSR entry point for prerendering SEO pages at build time.
|
|
|
|
|
*
|
|
|
|
|
* Used by scripts/prerender-seo.mjs via Vite's ssrLoadModule.
|
|
|
|
|
* Renders each page component to an HTML string so the prerender script
|
|
|
|
|
* can inject it into the static dist/index.html per route.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import React from 'react';
|
|
|
|
|
import { renderToString } from 'react-dom/server';
|
|
|
|
|
import { MemoryRouter } from 'react-router-dom';
|
|
|
|
|
import { SEO_ROUTES } from './seoRoutes';
|
|
|
|
|
|
|
|
|
|
// ── SEO page components ─────────────────────────────────────────────────────
|
2026-04-14 01:22:08 +07:00
|
|
|
import { exampleProjects } from './data/examples';
|
2026-03-25 10:08:46 +07:00
|
|
|
import { LandingPage } from './pages/LandingPage';
|
|
|
|
|
import { ExamplesPage } from './pages/ExamplesPage';
|
|
|
|
|
import { ArduinoSimulatorPage } from './pages/ArduinoSimulatorPage';
|
|
|
|
|
import { ArduinoEmulatorPage } from './pages/ArduinoEmulatorPage';
|
|
|
|
|
import { AtmegaSimulatorPage } from './pages/AtmegaSimulatorPage';
|
|
|
|
|
import { ArduinoMegaSimulatorPage } from './pages/ArduinoMegaSimulatorPage';
|
|
|
|
|
import { Esp32SimulatorPage } from './pages/Esp32SimulatorPage';
|
|
|
|
|
import { Esp32S3SimulatorPage } from './pages/Esp32S3SimulatorPage';
|
|
|
|
|
import { Esp32C3SimulatorPage } from './pages/Esp32C3SimulatorPage';
|
|
|
|
|
import { RaspberryPiPicoSimulatorPage } from './pages/RaspberryPiPicoSimulatorPage';
|
|
|
|
|
import { RaspberryPiSimulatorPage } from './pages/RaspberryPiSimulatorPage';
|
|
|
|
|
import { Velxio2Page } from './pages/Velxio2Page';
|
2026-04-24 21:42:47 +07:00
|
|
|
import { Velxio25Page } from './pages/Velxio25Page';
|
2026-03-25 10:08:46 +07:00
|
|
|
import { DocsPage } from './pages/DocsPage';
|
2026-04-14 01:22:08 +07:00
|
|
|
import { ExampleDetailPage } from './pages/ExampleDetailPage';
|
2026-03-25 10:08:46 +07:00
|
|
|
|
|
|
|
|
// Map route paths to their React component
|
|
|
|
|
const ROUTE_COMPONENTS: Record<string, React.FC> = {
|
|
|
|
|
'/': LandingPage,
|
|
|
|
|
'/examples': ExamplesPage,
|
|
|
|
|
'/arduino-simulator': ArduinoSimulatorPage,
|
|
|
|
|
'/arduino-emulator': ArduinoEmulatorPage,
|
|
|
|
|
'/atmega328p-simulator': AtmegaSimulatorPage,
|
|
|
|
|
'/arduino-mega-simulator': ArduinoMegaSimulatorPage,
|
|
|
|
|
'/esp32-simulator': Esp32SimulatorPage,
|
|
|
|
|
'/esp32-s3-simulator': Esp32S3SimulatorPage,
|
|
|
|
|
'/esp32-c3-simulator': Esp32C3SimulatorPage,
|
|
|
|
|
'/raspberry-pi-pico-simulator': RaspberryPiPicoSimulatorPage,
|
|
|
|
|
'/raspberry-pi-simulator': RaspberryPiSimulatorPage,
|
|
|
|
|
'/v2': Velxio2Page,
|
2026-04-24 21:42:47 +07:00
|
|
|
'/v2-5': Velxio25Page,
|
2026-03-25 10:08:46 +07:00
|
|
|
// Docs sections — all use DocsPage with different URL params
|
|
|
|
|
'/docs': DocsPage,
|
|
|
|
|
'/docs/intro': DocsPage,
|
|
|
|
|
'/docs/getting-started': DocsPage,
|
|
|
|
|
'/docs/emulator': DocsPage,
|
|
|
|
|
'/docs/esp32-emulation': DocsPage,
|
|
|
|
|
'/docs/riscv-emulation': DocsPage,
|
|
|
|
|
'/docs/rp2040-emulation': DocsPage,
|
|
|
|
|
'/docs/raspberry-pi3-emulation': DocsPage,
|
|
|
|
|
'/docs/components': DocsPage,
|
|
|
|
|
'/docs/architecture': DocsPage,
|
refactor: rename wokwi-libs/ → third-party/
The directory grew well beyond Wokwi-only contents: it now hosts
lcgamboa's QEMU fork (qemu-lcgamboa), Espressif's esp32-camera, the
ngspice WASM build, fritzing-parts, picowi, an alternative QEMU
(qemu-esp32), the 100_Days_100_IoT_Projects examples repo, and
Wokwi's own avr8js/rp2040js/wokwi-elements/wokwi-features/wokwi-boards.
"wokwi-libs" was misleading — half the contents have nothing to do
with Wokwi. "third-party/" is the standard convention for vendored
external dependencies.
Mechanical changes:
Path rename:
wokwi-libs/ → third-party/
update-wokwi-libs.bat → update-third-party.bat
docs/WOKWI_LIBS.md → docs/THIRD_PARTY.md
Submodule reconfiguration:
.gitmodules — 4 path= and section names updated
.git/modules/wokwi-libs/ → .git/modules/third-party/
each submodule's .git file rewired to ../../.git/modules/third-party/<name>
Reference updates (~80 files): vite.config.ts aliases, Dockerfile
COPY paths, GH Actions workflow steps, build_qemu_*.sh, all
docs/* and test/*/autosearch/* entries that mention the path,
package-lock.json file: dependencies, .gitignore patterns,
sitemap.xml + index.html SEO blurbs, scripts/generate-component-*,
.dockerignore, .idea/vcs.xml. Bulk replaced both `wokwi-libs/`
(path) and bare `wokwi-libs` (textual mentions in docs/comments).
Verified:
- npx tsc -b --noEmit produces no new errors related to these paths
- vite.config.ts aliases now point at ../third-party/avr8js etc.
- All 4 git submodules (avr8js, rp2040js, wokwi-elements,
wokwi-features) are linked under third-party/ with their
worktrees re-populated and config files referencing the new path
- `grep -r wokwi-libs` returns zero hits outside node_modules,
.vite, frontend/dist, third-party/ (upstream submodule contents),
*.pyc caches, and *.dll.pre-camera rollback binaries
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 10:58:57 +07:00
|
|
|
'/docs/third-party': DocsPage,
|
2026-03-25 10:08:46 +07:00
|
|
|
'/docs/mcp': DocsPage,
|
|
|
|
|
'/docs/setup': DocsPage,
|
|
|
|
|
'/docs/roadmap': DocsPage,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns all routes that have both seoMeta and a renderable component.
|
|
|
|
|
*/
|
|
|
|
|
export function getPrerenderedRoutes() {
|
2026-04-22 02:45:45 +07:00
|
|
|
return SEO_ROUTES.filter((r) => r.seoMeta && ROUTE_COMPONENTS[r.path]);
|
2026-03-25 10:08:46 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Render a route's page component to an HTML string.
|
|
|
|
|
*/
|
|
|
|
|
export function render(path: string): string {
|
|
|
|
|
const Component = ROUTE_COMPONENTS[path];
|
|
|
|
|
if (!Component) return '';
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
return renderToString(
|
|
|
|
|
<MemoryRouter initialEntries={[path]}>
|
|
|
|
|
<Component />
|
2026-04-22 02:45:45 +07:00
|
|
|
</MemoryRouter>,
|
2026-03-25 10:08:46 +07:00
|
|
|
);
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.warn(` ⚠ SSR render failed for ${path}:`, (err as Error).message);
|
|
|
|
|
return '';
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-04-14 01:22:08 +07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns all example routes to prerender, one per example project.
|
|
|
|
|
*/
|
|
|
|
|
export function getPrerenderedExampleRoutes() {
|
|
|
|
|
return exampleProjects.map((e) => ({
|
|
|
|
|
path: `/examples/${e.id}`,
|
|
|
|
|
title: `${e.title} — Free Arduino Simulator Example | Velxio`,
|
|
|
|
|
description: `${e.description}. Run this example free in your browser — no install, no account required.`,
|
|
|
|
|
url: `https://velxio.dev/examples/${e.id}`,
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Render an example detail page to an HTML string.
|
|
|
|
|
*/
|
|
|
|
|
export function renderExample(exampleId: string): string {
|
|
|
|
|
try {
|
|
|
|
|
return renderToString(
|
|
|
|
|
<MemoryRouter initialEntries={[`/examples/${exampleId}`]}>
|
|
|
|
|
<ExampleDetailPage />
|
2026-04-22 02:45:45 +07:00
|
|
|
</MemoryRouter>,
|
2026-04-14 01:22:08 +07:00
|
|
|
);
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.warn(` ⚠ SSR render failed for /examples/${exampleId}:`, (err as Error).message);
|
|
|
|
|
return '';
|
|
|
|
|
}
|
|
|
|
|
}
|