@pyreon/create-zero 0.1.1

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.
@@ -0,0 +1,97 @@
1
+ import { useHead } from '@pyreon/head'
2
+ import { useLoaderData } from '@pyreon/router'
3
+ import type { LoaderContext } from '@pyreon/zero'
4
+ import { Link } from '@pyreon/zero/link'
5
+
6
+ interface Post {
7
+ id: number
8
+ title: string
9
+ excerpt: string
10
+ body: string
11
+ author: string
12
+ date: string
13
+ }
14
+
15
+ const POSTS: Record<string, Post> = {
16
+ '1': {
17
+ id: 1,
18
+ title: 'Getting Started with Pyreon Zero',
19
+ excerpt: 'Learn how to build your first app.',
20
+ body: "Pyreon Zero makes it incredibly easy to build modern web applications. Start by creating a new project with `bun create zero my-app`, then drop your first route file into `src/routes/`. The file-based router automatically picks up new files and generates the route tree for you.\n\nEvery route can export a `loader` for server-side data fetching, a `guard` for navigation protection, and `meta` for SEO metadata. The component itself uses JSX with Pyreon's signal-based reactivity — no virtual DOM overhead, just surgical DOM updates.",
21
+ author: 'Zero Team',
22
+ date: '2026-03-01',
23
+ },
24
+ '2': {
25
+ id: 2,
26
+ title: 'Understanding Signals',
27
+ excerpt: 'Deep dive into fine-grained reactivity.',
28
+ body: "Signals are the foundation of Pyreon's reactivity system. Unlike the virtual DOM approach used by React, signals track exactly which DOM nodes depend on which pieces of state. When a signal changes, only the precise text nodes or attributes that reference it are updated.\n\nThis means your app does zero diffing, zero reconciliation, and zero unnecessary re-renders. A counter component that updates a number on screen? Only that one text node is touched. Everything else stays completely untouched.",
29
+ author: 'Zero Team',
30
+ date: '2026-03-05',
31
+ },
32
+ '3': {
33
+ id: 3,
34
+ title: 'Server-Side Rendering Made Simple',
35
+ excerpt: 'Pick the right strategy for every page.',
36
+ body: 'Zero supports four rendering strategies out of the box: SSR (server-side rendering), SSG (static site generation), ISR (incremental static regeneration), and SPA (single-page application). You can set a default mode in your config and override it per-route.\n\nSSR renders fresh HTML on every request. SSG pre-renders pages at build time. ISR combines both — serving cached static pages while revalidating in the background. SPA skips server rendering entirely for fully client-side pages.',
37
+ author: 'Zero Team',
38
+ date: '2026-03-08',
39
+ },
40
+ '4': {
41
+ id: 4,
42
+ title: 'Deploying to Production',
43
+ excerpt: 'From build to production with any platform.',
44
+ body: "Zero's adapter system makes deployment straightforward. Choose your target platform — Node.js, Bun, Vercel, Cloudflare Workers, or Netlify — and Zero generates the right output for that platform.\n\nThe Node adapter creates a standalone HTTP server. The Bun adapter leverages Bun.serve() for maximum performance. The static adapter exports a fully pre-rendered site ready for any CDN or static hosting platform.",
45
+ author: 'Zero Team',
46
+ date: '2026-03-10',
47
+ },
48
+ '5': {
49
+ id: 5,
50
+ title: 'Optimizing Performance',
51
+ excerpt: 'Built-in performance features.',
52
+ body: 'Zero includes a comprehensive performance toolkit. The font plugin automatically optimizes Google Fonts with preconnect hints and font-display:swap. The <Image> component provides lazy loading with IntersectionObserver, responsive srcset, and blur-up placeholders.\n\nThe <Link> component prefetches routes on hover or viewport entry, making navigation feel instant. Built-in cache middleware sets optimal Cache-Control headers — immutable caching for hashed assets, stale-while-revalidate for pages.',
53
+ author: 'Zero Team',
54
+ date: '2026-03-12',
55
+ },
56
+ }
57
+
58
+ export async function loader(ctx: LoaderContext) {
59
+ await new Promise((r) => setTimeout(r, 50))
60
+ const post = POSTS[ctx.params.id]
61
+ if (!post) throw new Error('Post not found')
62
+ return { post }
63
+ }
64
+
65
+ export default function PostDetail() {
66
+ const data = useLoaderData<{ post: Post }>()
67
+ const post = data.post
68
+
69
+ useHead({
70
+ title: `${post.title} — Pyreon Zero`,
71
+ meta: [{ name: 'description', content: post.excerpt }],
72
+ })
73
+
74
+ return (
75
+ <article class="post-detail">
76
+ <Link
77
+ href="/posts"
78
+ style="color: var(--c-text-muted); font-size: 0.85rem; display: inline-block; margin-bottom: var(--space-lg);"
79
+ >
80
+ ← Back to Posts
81
+ </Link>
82
+
83
+ <h1>{post.title}</h1>
84
+
85
+ <div class="post-meta">
86
+ <span>{post.author}</span>
87
+ <span>{post.date}</span>
88
+ </div>
89
+
90
+ <div class="post-body">
91
+ {post.body.split('\n\n').map((paragraph) => (
92
+ <p style="margin-bottom: var(--space-lg);">{paragraph}</p>
93
+ ))}
94
+ </div>
95
+ </article>
96
+ )
97
+ }
@@ -0,0 +1,115 @@
1
+ import { useHead } from '@pyreon/head'
2
+ import { useLoaderData } from '@pyreon/router'
3
+ import type { LoaderContext } from '@pyreon/zero'
4
+ import { Link } from '@pyreon/zero/link'
5
+
6
+ interface Post {
7
+ id: number
8
+ title: string
9
+ excerpt: string
10
+ }
11
+
12
+ const POSTS: Post[] = [
13
+ {
14
+ id: 1,
15
+ title: 'Getting Started with Pyreon Zero',
16
+ excerpt:
17
+ 'Learn how to build your first app with file-based routing, SSR, and signals.',
18
+ },
19
+ {
20
+ id: 2,
21
+ title: 'Understanding Signals',
22
+ excerpt:
23
+ 'Deep dive into fine-grained reactivity — how signals replace the virtual DOM.',
24
+ },
25
+ {
26
+ id: 3,
27
+ title: 'Server-Side Rendering Made Simple',
28
+ excerpt:
29
+ 'SSR, SSG, ISR — pick the right strategy for every page in your app.',
30
+ },
31
+ {
32
+ id: 4,
33
+ title: 'Deploying to Production',
34
+ excerpt:
35
+ 'From bun build to production with Node, Bun, Vercel, or Cloudflare adapters.',
36
+ },
37
+ {
38
+ id: 5,
39
+ title: 'Optimizing Performance',
40
+ excerpt:
41
+ 'Font loading, image optimization, smart caching, and link prefetching out of the box.',
42
+ },
43
+ ]
44
+
45
+ export async function loader(_ctx: LoaderContext) {
46
+ // Simulate network delay — in a real app, fetch from a database or API
47
+ await new Promise((r) => setTimeout(r, 100))
48
+ return { posts: POSTS }
49
+ }
50
+
51
+ export default function PostsIndex() {
52
+ const data = useLoaderData<{ posts: Post[] }>()
53
+
54
+ useHead({
55
+ title: 'Posts — Pyreon Zero',
56
+ meta: [
57
+ {
58
+ name: 'description',
59
+ content: "Example posts showcasing Zero's data loading.",
60
+ },
61
+ ],
62
+ })
63
+
64
+ return (
65
+ <>
66
+ <div class="page-header">
67
+ <span class="badge">Data Loading</span>
68
+ <h1 style="margin-top: var(--space-md);">Posts</h1>
69
+ <p>
70
+ Each post is loaded via a <code>loader</code> function — server-side
71
+ data fetching that runs before the route renders.
72
+ </p>
73
+ </div>
74
+
75
+ <div class="posts-grid">
76
+ {data.posts.map((post) => (
77
+ <Link
78
+ href={`/posts/${post.id}`}
79
+ class="card post-card"
80
+ prefetch="hover"
81
+ >
82
+ <span class="post-id">#{post.id}</span>
83
+ <div>
84
+ <h3>{post.title}</h3>
85
+ <p>{post.excerpt}</p>
86
+ </div>
87
+ </Link>
88
+ ))}
89
+ </div>
90
+
91
+ <div
92
+ class="code-block"
93
+ style="max-width: 520px; margin: var(--space-2xl) auto 0;"
94
+ >
95
+ <div class="code-block-header">
96
+ <span>posts/index.tsx</span>
97
+ </div>
98
+ <pre>
99
+ <code>
100
+ <span class="cm">{'// Export a loader — runs on the server'}</span>
101
+ <span class="kw">export async function</span>{' '}
102
+ <span class="fn">loader</span>(ctx) {'{'}
103
+ <span class="kw">const</span> posts = <span class="kw">await</span>{' '}
104
+ db.posts.<span class="fn">findMany</span>()
105
+ <span class="kw">return</span> {'{'} posts {'}'}
106
+ {'}'}
107
+ <span class="cm">{'// Access data in the component'}</span>
108
+ <span class="kw">const</span> data ={' '}
109
+ <span class="fn">useLoaderData</span>()
110
+ </code>
111
+ </pre>
112
+ </div>
113
+ </>
114
+ )
115
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "jsx": "preserve",
7
+ "jsxImportSource": "@pyreon/core",
8
+ "strict": true,
9
+ "skipLibCheck": true,
10
+ "esModuleInterop": true,
11
+ "isolatedModules": true,
12
+ "noEmit": true,
13
+ "types": ["vite/client"]
14
+ },
15
+ "include": ["src", "env.d.ts"]
16
+ }
@@ -0,0 +1,29 @@
1
+ import pyreon from '@pyreon/vite-plugin'
2
+ import zero from '@pyreon/zero'
3
+ import { fontPlugin } from '@pyreon/zero/font'
4
+ import { seoPlugin } from '@pyreon/zero/seo'
5
+
6
+ export default {
7
+ plugins: [
8
+ pyreon(),
9
+ zero({ mode: 'ssr', ssr: { mode: 'stream' } }),
10
+
11
+ // Google Fonts — self-hosted at build time, CDN in dev
12
+ fontPlugin({
13
+ google: ['Inter:wght@400;500;600;700;800', 'JetBrains Mono:wght@400'],
14
+ // Size-adjusted fallbacks to eliminate CLS while fonts load
15
+ fallbacks: {
16
+ Inter: { fallback: 'Arial', sizeAdjust: 1.07, ascentOverride: 90 },
17
+ },
18
+ }),
19
+
20
+ // Generate sitemap.xml and robots.txt at build time
21
+ seoPlugin({
22
+ sitemap: { origin: 'https://example.com' },
23
+ robots: {
24
+ rules: [{ userAgent: '*', allow: ['/'] }],
25
+ sitemap: 'https://example.com/sitemap.xml',
26
+ },
27
+ }),
28
+ ],
29
+ }