@uniweb/runtime 0.5.15 → 0.5.16

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.
Files changed (2) hide show
  1. package/package.json +2 -2
  2. package/src/index.jsx +45 -10
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniweb/runtime",
3
- "version": "0.5.15",
3
+ "version": "0.5.16",
4
4
  "description": "Minimal runtime for loading Uniweb foundations",
5
5
  "type": "module",
6
6
  "exports": {
@@ -31,7 +31,7 @@
31
31
  "node": ">=20.19"
32
32
  },
33
33
  "dependencies": {
34
- "@uniweb/core": "0.4.3"
34
+ "@uniweb/core": "0.4.4"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@vitejs/plugin-react": "^4.5.2",
package/src/index.jsx CHANGED
@@ -130,6 +130,28 @@ async function loadFoundation(source) {
130
130
  }
131
131
  }
132
132
 
133
+ /**
134
+ * Load extensions (secondary foundations) in parallel
135
+ * @param {Array<string|Object>} urls - Extension URLs or {url, cssUrl} objects
136
+ * @param {Object} uniwebInstance - The Uniweb instance to register extensions on
137
+ */
138
+ async function loadExtensions(urls, uniwebInstance) {
139
+ if (!urls?.length) return
140
+
141
+ const results = await Promise.allSettled(
142
+ urls.map(url => loadFoundation(url))
143
+ )
144
+
145
+ for (let i = 0; i < results.length; i++) {
146
+ if (results[i].status === 'fulfilled') {
147
+ uniwebInstance.registerExtension(results[i].value)
148
+ console.log(`[Runtime] Extension loaded: ${urls[i]}`)
149
+ } else {
150
+ console.warn(`[Runtime] Extension failed to load: ${urls[i]}`, results[i].reason)
151
+ }
152
+ }
153
+ }
154
+
133
155
  /**
134
156
  * Map friendly family names to react-icons codes
135
157
  * The existing CDN uses react-icons structure: /{familyCode}/{familyCode}-{name}.svg
@@ -411,6 +433,12 @@ async function initRuntime(foundationSource, options = {}) {
411
433
  uniwebInstance.setFoundationConfig(foundation.capabilities)
412
434
  }
413
435
 
436
+ // Load extensions (secondary foundations)
437
+ const extensions = configData?.config?.extensions
438
+ if (extensions?.length) {
439
+ await loadExtensions(extensions, uniwebInstance)
440
+ }
441
+
414
442
  // Render the app
415
443
  render({ development, basename })
416
444
 
@@ -452,15 +480,23 @@ async function initRuntime(foundationSource, options = {}) {
452
480
  /**
453
481
  * Simplified entry point for sites
454
482
  *
455
- * Reads configuration from (in order of priority):
456
- * 1. __DATA__ element (dynamic backends) - combined foundation config + site content
457
- * 2. Build-time __FOUNDATION_CONFIG__ (static builds) - foundation config only
483
+ * Template main.js calls this with config + foundation/styles promises:
484
+ *
485
+ * start({
486
+ * config: __FOUNDATION_CONFIG__,
487
+ * styles: import('#foundation/styles'),
488
+ * foundation: import('#foundation')
489
+ * })
490
+ *
491
+ * In runtime mode, the foundation/styles promises resolve to noop modules
492
+ * (configured by the site Vite plugin) and are ignored.
458
493
  *
459
494
  * @param {Object} options
495
+ * @param {Object} options.config - Build-time config from __FOUNDATION_CONFIG__
460
496
  * @param {Promise} options.foundation - Promise from import('#foundation')
461
497
  * @param {Promise} options.styles - Promise from import('#foundation/styles')
462
498
  */
463
- async function start({ foundation, styles } = {}) {
499
+ async function start({ config, foundation, styles } = {}) {
464
500
  // Try __DATA__ first (dynamic backends inject combined config + content)
465
501
  const data = await decodeData()
466
502
 
@@ -472,15 +508,14 @@ async function start({ foundation, styles } = {}) {
472
508
  )
473
509
  }
474
510
 
475
- // Static build mode - use build-time config
476
- const config =
477
- typeof __FOUNDATION_CONFIG__ !== 'undefined' ? __FOUNDATION_CONFIG__ : { mode: 'bundled' }
511
+ // Use provided config, or fall back to bundled mode
512
+ const mode = config?.mode ?? 'bundled'
478
513
 
479
- if (config.mode === 'runtime') {
480
- // Runtime mode (foundation URL in site.yml)
514
+ if (mode === 'runtime') {
515
+ // Runtime mode - foundation loaded from URL
481
516
  return initRuntime({ url: config.url, cssUrl: config.cssUrl })
482
517
  } else {
483
- // Bundled mode - foundation included in build
518
+ // Bundled mode - use the provided foundation/styles promises
484
519
  const [foundationModule] = await Promise.all([foundation, styles])
485
520
  return initRuntime(foundationModule)
486
521
  }