From source to page
What {vite 'src/main.js'} writes for this request and why: the manifest the build left, the chunks of each island, and the dev server that takes over while it runs.
{vite}$padViteBuildbuild/hot
type=modulemodulepreload
Live
The build: www/islands/build/
Start npm run dev in _frontend/ and reload: {vite} then asks the dev server instead.
What {vite 'src/main.js'} wrote into the head
<script type="module" src="/pad/islands/build/assets/main-2Gb33P07.js"></script>
The server's time, ticking in a Solid island
-
The manifest - every source and what it became
| Source | File | Kind | CSS |
|---|---|---|---|
src/adapters/preact.js | assets/preact-IvGl7Sg9.js | loaded on demand | |
src/adapters/react.js | assets/react-DMbKTkY7.js | loaded on demand | |
src/adapters/solid.js | assets/solid-DNc0Ypxi.js | loaded on demand | |
src/adapters/svelte.js | assets/svelte-D94bdpAJ.js | loaded on demand | |
src/adapters/vue.js | assets/vue-D2b7WoT0.js | loaded on demand | |
src/islands/CartBadge.svelte | assets/CartBadge-Da_ed-6b.js | loaded on demand | assets/CartBadge-Bv7sRs5B.css |
src/islands/CartSummary.vue | assets/CartSummary-Cp-v3eII.js | loaded on demand | assets/CartSummary-F7s383VX.css |
src/islands/Clock.solid.jsx | assets/Clock.solid-Ct-gs6od.js | loaded on demand | |
src/islands/Counter.preact.js | assets/Counter.preact-v7abP-yK.js | loaded on demand | |
src/islands/Counter.react.jsx | assets/Counter.react-BFt9JEJ7.js | loaded on demand | |
src/islands/Counter.solid.jsx | assets/Counter.solid-B_zGEf73.js | loaded on demand | |
src/islands/Counter.svelte | assets/Counter-Batfu1wT.js | loaded on demand | |
src/islands/Counter.vue | assets/Counter-h07JzQ8B.js | loaded on demand | |
src/islands/LoadLog.preact.js | assets/LoadLog.preact-CIBY1b39.js | loaded on demand | |
src/islands/OrderCard.react.tsx | assets/OrderCard.react-C735Z2LI.js | loaded on demand | |
src/islands/Shelf.react.jsx | assets/Shelf.react-DiwPuzdd.js | loaded on demand | |
src/main.js | assets/main-2Gb33P07.js | entry | |
How it is built
PAD, on the server the islands, built by Vite
<div class="cols-2">
<div>
<div class="panel-title">{if $dev}The dev server runs: {$dev}{else}The build: www/islands/build/{/if}</div>
<p class="muted small">{if $dev}{open}vite{close} asks the dev server - every save shows at once.{else}Start <code>npm run dev</code> in <code>_frontend/</code> and reload: {open}vite{close} then asks the dev server instead.{/if}</p>
<div class="panel-title" style="margin-top: 18px">What {open}vite 'src/main.js'{close} wrote into the head</div>
{echo $written | highlight('html')}
</div>
<div>
<div class="panel-title">The server's time, ticking in a Solid island</div>
<div class="clock-box" data-island="Clock" data-props="{^clock}"><span class="clock">-</span></div>
</div>
</div>
{if $sourceCount}
<div class="panel-title" style="margin-top: 26px">The manifest - every source and what it became</div>
<table class="table">
<thead><tr><th>Source</th><th>File</th><th>Kind</th><th>CSS</th></tr></thead>
<tbody>
{sources}<tr><td><code>{$source}</code></td><td><code>{$file}</code></td><td>{$kind}</td><td><code>{$css}</code></td></tr>{/sources}
</tbody>
</table>
{/if}<?php
// What {vite 'src/main.js'} wrote into this page's <head>, and where it came from: the
// manifest of the build - every source and the file it became - or the dev server, while it
// runs. The clock is a Solid island started from the server's time.
$dev = padViteDev ();
$manifest = $dev === '' ? ( padViteManifest () ?? [] ) : [];
$written = trim ( padViteTags ( [ 'src/main.js' ], FALSE, FALSE ) );
$sources = [];
foreach ( $manifest as $source => $one )
if ( ! str_starts_with ( $source, '_' ) )
$sources [] = [ 'source' => $source,
'file' => $one ['file'],
'kind' => ( $one ['isEntry'] ?? FALSE ) ? 'entry' : ( ( $one ['isDynamicEntry'] ?? FALSE ) ? 'loaded on demand' : 'chunk' ),
'css' => implode ( ', ', $one ['css'] ?? [] ) ];
$sourceCount = count ( $sources );
$clock = [ 'now' => time () ];
?>// The build of the islands application: the components of every framework in src/, made
// into www/islands/build/ with a manifest - {vite 'src/main.js'} in the templates reads it.
//
// npm install
// npm run build www/islands/build/ - what the pages load
// npm run dev the dev server: its address goes into build/hot, and {vite} asks it
//
// Each framework compiles its own files: React *.react.jsx/tsx, Solid *.solid.jsx, Vue
// *.vue, Svelte *.svelte; Preact needs no compiler here - its components are written with
// htm. PAD_ISLANDS_WWW names www/islands/ when the project is built from a copy elsewhere.
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import vue from '@vitejs/plugin-vue';
import { svelte } from '@sveltejs/vite-plugin-svelte';
import solid from 'vite-plugin-solid';
const here = path.dirname(fileURLToPath(import.meta.url));
const www = process.env.PAD_ISLANDS_WWW || path.resolve(here, '../../../www/islands');
const outDir = path.join(www, 'build');
// The dev server's address in build/hot while it runs, gone when it stops: {vite} asks the
// dev server while the file is there, and the build when it is not.
function padHot() {
const hot = path.join(outDir, 'hot');
const clear = () => fs.rmSync(hot, { force: true });
return {
name: 'pad-hot',
apply: 'serve',
configureServer(server) {
server.httpServer?.once('listening', () => {
const { port } = server.httpServer.address();
fs.mkdirSync(outDir, { recursive: true });
fs.writeFileSync(hot, `http://localhost:${port}`);
});
// however the dev server stops - Ctrl-C, a kill, its own exit - the file goes with it
server.httpServer?.once('close', clear);
process.once('exit', clear);
for (const signal of ['SIGINT', 'SIGTERM', 'SIGHUP'])
process.once(signal, () => process.exit());
}
};
}
export default defineConfig({
root: here,
base: './',
plugins: [
react({ include: /\.react\.[jt]sx$/ }),
solid({ include: /\.solid\.jsx$/ }),
vue(),
svelte(),
padHot()
],
build: {
outDir,
emptyOutDir: true,
manifest: true,
rollupOptions: { input: [ 'src/main.js' ] }
},
server: { port: 5173, strictPort: true, cors: true }
});{
"name": "pad-islands",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"types": "cd ../../.. && php apps/cli/pad types islands examples/typed --out=apps/islands/_frontend/src/types/pad.d.ts",
"check": "tsc --noEmit"
},
"devDependencies": {
"vite": "^6",
"@vitejs/plugin-react": "^4",
"@vitejs/plugin-vue": "^5",
"@sveltejs/vite-plugin-svelte": "^5",
"vite-plugin-solid": "^2",
"typescript": "^5",
"@types/react": "^18.3",
"@types/react-dom": "^18.3"
},
"dependencies": {
"react": "^18.3.1",
"react-dom": "^18.3.1",
"vue": "^3.5",
"svelte": "^5",
"preact": "^10",
"htm": "^3",
"solid-js": "^1.9"
}
}// A clock in Solid, started from the server's time: only the text node changes each second.
import { createSignal, onCleanup } from 'solid-js';
export default function Clock(props) {
const offset = props.now * 1000 - Date.now();
const [now, setNow] = createSignal(new Date(Date.now() + offset));
const timer = setInterval(() => setNow(new Date(Date.now() + offset)), 1000);
onCleanup(() => clearInterval(timer));
return <span class="clock">{now().toLocaleTimeString()}</span>;
}