@uniweb/build 0.1.21 → 0.1.22

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniweb/build",
3
- "version": "0.1.21",
3
+ "version": "0.1.22",
4
4
  "description": "Build tooling for the Uniweb Component Web Platform",
5
5
  "type": "module",
6
6
  "exports": {
@@ -59,7 +59,7 @@
59
59
  "@tailwindcss/vite": "^4.0.0",
60
60
  "@vitejs/plugin-react": "^4.0.0 || ^5.0.0",
61
61
  "vite-plugin-svgr": "^4.0.0",
62
- "@uniweb/core": "0.1.9"
62
+ "@uniweb/core": "0.1.10"
63
63
  },
64
64
  "peerDependenciesMeta": {
65
65
  "vite": {
package/src/prerender.js CHANGED
@@ -118,11 +118,21 @@ export async function prerenderSite(siteDir, options = {}) {
118
118
  const pages = uniweb.activeWebsite.pages
119
119
 
120
120
  for (const page of pages) {
121
- const route = page.route
122
- onProgress(`Rendering ${route}...`)
121
+ // Determine which routes to render this page at
122
+ // Index pages are rendered at both their actual route and their nav route
123
+ const routesToRender = [page.route]
124
+ if (page.isIndex) {
125
+ const navRoute = page.getNavRoute()
126
+ if (navRoute !== page.route) {
127
+ routesToRender.push(navRoute)
128
+ }
129
+ }
130
+
131
+ // Render once, output to multiple paths
132
+ onProgress(`Rendering ${routesToRender[0]}...`)
123
133
 
124
134
  // Set this as the active page
125
- uniweb.activeWebsite.setActivePage(route)
135
+ uniweb.activeWebsite.setActivePage(page.route)
126
136
 
127
137
  // Create the page element
128
138
  // Note: We don't need StaticRouter for SSG since we're just rendering
@@ -134,7 +144,7 @@ export async function prerenderSite(siteDir, options = {}) {
134
144
  try {
135
145
  renderedContent = renderToString(element)
136
146
  } catch (err) {
137
- console.warn(`Warning: Failed to render ${route}: ${err.message}`)
147
+ console.warn(`Warning: Failed to render ${page.route}: ${err.message}`)
138
148
  if (process.env.DEBUG) {
139
149
  console.error(err.stack)
140
150
  }
@@ -144,13 +154,15 @@ export async function prerenderSite(siteDir, options = {}) {
144
154
  // Inject into shell
145
155
  const html = injectContent(htmlShell, renderedContent, page, siteContent)
146
156
 
147
- // Determine output path
148
- const outputPath = getOutputPath(distDir, route)
149
- await mkdir(dirname(outputPath), { recursive: true })
150
- await writeFile(outputPath, html)
157
+ // Output to all routes for this page
158
+ for (const route of routesToRender) {
159
+ const outputPath = getOutputPath(distDir, route)
160
+ await mkdir(dirname(outputPath), { recursive: true })
161
+ await writeFile(outputPath, html)
151
162
 
152
- renderedFiles.push(outputPath)
153
- onProgress(` → ${outputPath.replace(distDir, 'dist')}`)
163
+ renderedFiles.push(outputPath)
164
+ onProgress(` → ${outputPath.replace(distDir, 'dist')}`)
165
+ }
154
166
  }
155
167
 
156
168
  onProgress(`Pre-rendered ${renderedFiles.length} pages`)
@@ -351,11 +351,10 @@ async function processPage(pagePath, pageName, siteRoot, { isIndex = false, pare
351
351
  }
352
352
 
353
353
  // Determine route
354
+ // All pages get their actual folder-based route (no special treatment for index)
355
+ // The isIndex flag marks which page should also be accessible at the parent route
354
356
  let route
355
- if (isIndex) {
356
- // Index page gets the parent route
357
- route = parentRoute
358
- } else if (pageName.startsWith('@')) {
357
+ if (pageName.startsWith('@')) {
359
358
  // Special pages (layout areas) keep their @ prefix
360
359
  route = parentRoute === '/' ? `/@${pageName.slice(1)}` : `${parentRoute}/@${pageName.slice(1)}`
361
360
  } else {
@@ -369,6 +368,7 @@ async function processPage(pagePath, pageName, siteRoot, { isIndex = false, pare
369
368
  return {
370
369
  page: {
371
370
  route,
371
+ isIndex, // Marks this page as the index for its parent route (accessible at parentRoute)
372
372
  title: pageConfig.title || pageName,
373
373
  description: pageConfig.description || '',
374
374
  label: pageConfig.label || null, // Short label for navigation (defaults to title)
@@ -295,7 +295,9 @@ export function siteContentPlugin(options = {}) {
295
295
 
296
296
  // Watch for content changes in dev mode
297
297
  if (shouldWatch) {
298
- const watchPath = resolve(resolvedSitePath, pagesDir)
298
+ const pagesPath = resolve(resolvedSitePath, pagesDir)
299
+ const siteYmlPath = resolve(resolvedSitePath, 'site.yml')
300
+ const themeYmlPath = resolve(resolvedSitePath, 'theme.yml')
299
301
 
300
302
  // Debounce rebuilds
301
303
  let rebuildTimeout = null
@@ -315,12 +317,33 @@ export function siteContentPlugin(options = {}) {
315
317
  }, 100)
316
318
  }
317
319
 
320
+ // Track all watchers for cleanup
321
+ const watchers = []
322
+
323
+ // Watch pages directory
318
324
  try {
319
- watcher = watch(watchPath, { recursive: true }, scheduleRebuild)
320
- console.log(`[site-content] Watching ${watchPath}`)
325
+ watchers.push(watch(pagesPath, { recursive: true }, scheduleRebuild))
326
+ console.log(`[site-content] Watching ${pagesPath}`)
321
327
  } catch (err) {
322
328
  console.warn('[site-content] Could not watch pages directory:', err.message)
323
329
  }
330
+
331
+ // Watch site.yml
332
+ try {
333
+ watchers.push(watch(siteYmlPath, scheduleRebuild))
334
+ } catch (err) {
335
+ // site.yml may not exist, that's ok
336
+ }
337
+
338
+ // Watch theme.yml
339
+ try {
340
+ watchers.push(watch(themeYmlPath, scheduleRebuild))
341
+ } catch (err) {
342
+ // theme.yml may not exist, that's ok
343
+ }
344
+
345
+ // Store watchers for cleanup
346
+ watcher = { close: () => watchers.forEach(w => w.close()) }
324
347
  }
325
348
 
326
349
  // Serve content and SEO files