@uniweb/build 0.4.1 → 0.4.2

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.4.1",
3
+ "version": "0.4.2",
4
4
  "description": "Build tooling for the Uniweb Component Web Platform",
5
5
  "type": "module",
6
6
  "exports": {
@@ -51,7 +51,7 @@
51
51
  },
52
52
  "optionalDependencies": {
53
53
  "@uniweb/content-reader": "1.1.1",
54
- "@uniweb/runtime": "0.5.0"
54
+ "@uniweb/runtime": "0.5.2"
55
55
  },
56
56
  "peerDependencies": {
57
57
  "vite": "^5.0.0 || ^6.0.0 || ^7.0.0",
@@ -60,7 +60,7 @@
60
60
  "@tailwindcss/vite": "^4.0.0",
61
61
  "@vitejs/plugin-react": "^4.0.0 || ^5.0.0",
62
62
  "vite-plugin-svgr": "^4.0.0",
63
- "@uniweb/core": "0.3.1"
63
+ "@uniweb/core": "0.3.3"
64
64
  },
65
65
  "peerDependenciesMeta": {
66
66
  "vite": {
package/src/prerender.js CHANGED
@@ -263,6 +263,43 @@ async function loadDependencies(siteDir) {
263
263
  guaranteeContentStructureSSR = runtimeMod.guaranteeContentStructure
264
264
  }
265
265
 
266
+ /**
267
+ * Pre-fetch icons from CDN and populate the Uniweb icon cache.
268
+ * This allows the Icon component to render SVGs synchronously during SSR
269
+ * instead of producing empty placeholders.
270
+ */
271
+ async function prefetchIcons(siteContent, uniweb, onProgress) {
272
+ const icons = siteContent.icons?.used || []
273
+ if (icons.length === 0) return
274
+
275
+ const cdnBase = siteContent.config?.icons?.cdnUrl || 'https://uniweb.github.io/icons'
276
+
277
+ onProgress(`Fetching ${icons.length} icons for SSR...`)
278
+
279
+ const results = await Promise.allSettled(
280
+ icons.map(async (iconRef) => {
281
+ const [family, name] = iconRef.split(':')
282
+ const url = `${cdnBase}/${family}/${family}-${name}.svg`
283
+ const response = await fetch(url)
284
+ if (!response.ok) throw new Error(`HTTP ${response.status}`)
285
+ const svg = await response.text()
286
+ uniweb.iconCache.set(`${family}:${name}`, svg)
287
+ })
288
+ )
289
+
290
+ const succeeded = results.filter(r => r.status === 'fulfilled').length
291
+ const failed = results.filter(r => r.status === 'rejected').length
292
+ if (failed > 0) {
293
+ console.warn(`[prerender] Fetched ${succeeded}/${icons.length} icons (${failed} failed)`)
294
+ }
295
+
296
+ // Store icon cache on siteContent for embedding in HTML
297
+ // This allows the client runtime to populate the cache before rendering
298
+ if (uniweb.iconCache.size > 0) {
299
+ siteContent._iconCache = Object.fromEntries(uniweb.iconCache)
300
+ }
301
+ }
302
+
266
303
  /**
267
304
  * Inline BlockRenderer for SSR
268
305
  * Uses React from prerender's scope to avoid module resolution issues
@@ -524,6 +561,9 @@ export async function prerenderSite(siteDir, options = {}) {
524
561
  uniweb.setFoundationConfig(foundation.capabilities)
525
562
  }
526
563
 
564
+ // Pre-fetch icons for SSR embedding
565
+ await prefetchIcons(siteContent, uniweb, onProgress)
566
+
527
567
  // Pre-render each page
528
568
  const pages = uniweb.activeWebsite.pages
529
569
  const website = uniweb.activeWebsite
@@ -640,6 +680,22 @@ function injectContent(shell, renderedContent, page, siteContent) {
640
680
  )
641
681
  }
642
682
 
683
+ // Inject icon cache so client can render icons immediately without CDN fetches
684
+ if (siteContent._iconCache) {
685
+ const iconScript = `<script id="__ICON_CACHE__" type="application/json">${JSON.stringify(siteContent._iconCache)}</script>`
686
+ if (html.includes('__ICON_CACHE__')) {
687
+ html = html.replace(
688
+ /<script[^>]*id="__ICON_CACHE__"[^>]*>[\s\S]*?<\/script>/,
689
+ iconScript
690
+ )
691
+ } else {
692
+ html = html.replace(
693
+ '</head>',
694
+ ` ${iconScript}\n </head>`
695
+ )
696
+ }
697
+ }
698
+
643
699
  return html
644
700
  }
645
701
 
@@ -287,6 +287,10 @@ export async function defineSiteConfig(options = {}) {
287
287
  },
288
288
 
289
289
  resolve: {
290
+ // Deduplicate React packages to prevent dual-instance issues
291
+ // Foundation externalizes React; when site bundles it, CJS and ESM
292
+ // copies can coexist without this, causing "useRef of null" errors
293
+ dedupe: ['react', 'react-dom', 'react/jsx-runtime', 'react/jsx-dev-runtime'],
290
294
  alias: {
291
295
  ...alias,
292
296
  ...resolveOverrides?.alias