@uniweb/runtime 0.2.6 → 0.2.8

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/runtime",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "description": "Minimal runtime for loading Uniweb foundations",
5
5
  "type": "module",
6
6
  "exports": {
@@ -29,7 +29,7 @@
29
29
  "node": ">=20.19"
30
30
  },
31
31
  "dependencies": {
32
- "@uniweb/core": "0.1.6"
32
+ "@uniweb/core": "0.1.7"
33
33
  },
34
34
  "peerDependencies": {
35
35
  "react": "^18.0.0 || ^19.0.0",
@@ -12,24 +12,26 @@
12
12
  * - right: Right sidebar/panel (from @right page)
13
13
  *
14
14
  * Custom Layouts:
15
- * Foundations can export a Layout component that receives pre-rendered areas as props:
15
+ * Foundations can provide a custom Layout via src/runtime.js:
16
16
  *
17
17
  * ```jsx
18
- * export const site = {
19
- * Layout: ({ page, website, header, body, footer, left, right }) => (
20
- * <div className="my-layout">
21
- * <header>{header}</header>
22
- * <aside>{left}</aside>
23
- * <main>{body}</main>
24
- * <aside>{right}</aside>
25
- * <footer>{footer}</footer>
26
- * </div>
27
- * )
18
+ * // src/runtime.js
19
+ * import Layout from './components/Layout'
20
+ *
21
+ * export default {
22
+ * Layout,
23
+ * props: {
24
+ * themeToggleEnabled: true,
25
+ * }
28
26
  * }
29
27
  * ```
28
+ *
29
+ * The Layout component receives pre-rendered areas as props:
30
+ * - page, website: Runtime context
31
+ * - header, body, footer: Pre-rendered React elements
32
+ * - left, right (or leftPanel, rightPanel): Sidebar panels
30
33
  */
31
34
 
32
- import React from 'react'
33
35
  import Blocks from './Blocks.jsx'
34
36
 
35
37
  /**
package/src/index.jsx CHANGED
@@ -19,6 +19,53 @@ import Blocks from './components/Blocks.jsx'
19
19
  // Core factory from @uniweb/core
20
20
  import { createUniweb } from '@uniweb/core'
21
21
 
22
+ /**
23
+ * Decode combined data from __DATA__ element
24
+ *
25
+ * Encoding is signaled via MIME type:
26
+ * - application/json: plain JSON (no compression)
27
+ * - application/gzip: gzip + base64 encoded
28
+ *
29
+ * @returns {Promise<{foundation: Object, content: Object}|null>}
30
+ */
31
+ async function decodeData() {
32
+ const el = document.getElementById('__DATA__')
33
+ if (!el?.textContent) return null
34
+
35
+ const raw = el.textContent
36
+
37
+ // Plain JSON (uncompressed)
38
+ if (el.type === 'application/json') {
39
+ try {
40
+ return JSON.parse(raw)
41
+ } catch {
42
+ return null
43
+ }
44
+ }
45
+
46
+ // Compressed (application/gzip or legacy application/octet-stream)
47
+ if (typeof DecompressionStream !== 'undefined') {
48
+ try {
49
+ const bytes = Uint8Array.from(atob(raw), c => c.charCodeAt(0))
50
+ const stream = new DecompressionStream('gzip')
51
+ const writer = stream.writable.getWriter()
52
+ writer.write(bytes)
53
+ writer.close()
54
+ const json = await new Response(stream.readable).text()
55
+ return JSON.parse(json)
56
+ } catch {
57
+ return null
58
+ }
59
+ }
60
+
61
+ // Fallback for old browsers: try plain JSON (server can detect User-Agent)
62
+ try {
63
+ return JSON.parse(raw)
64
+ } catch {
65
+ return null
66
+ }
67
+ }
68
+
22
69
  /**
23
70
  * Load foundation CSS from URL
24
71
  * @param {string} url - URL to foundation's CSS file
@@ -183,9 +230,9 @@ async function initRuntime(foundationSource, options = {}) {
183
230
  // Set the foundation on the runtime
184
231
  uniwebInstance.setFoundation(foundation)
185
232
 
186
- // Set foundation config if provided
187
- if (foundation.config || foundation.site) {
188
- uniwebInstance.setFoundationConfig(foundation.config || foundation.site)
233
+ // Set foundation config if provided (runtime is the new name, config/site are legacy)
234
+ if (foundation.runtime || foundation.config || foundation.site) {
235
+ uniwebInstance.setFoundationConfig(foundation.runtime || foundation.config || foundation.site)
189
236
  }
190
237
 
191
238
  // Render the app
@@ -229,26 +276,35 @@ async function initRuntime(foundationSource, options = {}) {
229
276
  /**
230
277
  * Simplified entry point for sites
231
278
  *
232
- * Reads foundation configuration from __FOUNDATION_CONFIG__ which is injected
233
- * by the Vite config based on site.yml settings.
279
+ * Reads configuration from (in order of priority):
280
+ * 1. __DATA__ element (dynamic backends) - combined foundation config + site content
281
+ * 2. Build-time __FOUNDATION_CONFIG__ (static builds) - foundation config only
234
282
  *
235
283
  * @param {Object} options
236
284
  * @param {Promise} options.foundation - Promise from import('#foundation')
237
285
  * @param {Promise} options.styles - Promise from import('#foundation/styles')
238
286
  */
239
287
  async function start({ foundation, styles } = {}) {
240
- // Read config injected by Vite's define option (from site.yml)
288
+ // Try __DATA__ first (dynamic backends inject combined config + content)
289
+ const data = await decodeData()
290
+
291
+ if (data) {
292
+ // Dynamic backend mode - foundation loaded from URL, content from data
293
+ return initRuntime(
294
+ { url: data.foundation.url, cssUrl: data.foundation.cssUrl },
295
+ { configData: data.content }
296
+ )
297
+ }
298
+
299
+ // Static build mode - use build-time config
241
300
  const config =
242
301
  typeof __FOUNDATION_CONFIG__ !== 'undefined' ? __FOUNDATION_CONFIG__ : { mode: 'bundled' }
243
302
 
244
303
  if (config.mode === 'runtime') {
245
- // Runtime mode: load foundation dynamically from URL
246
- return initRuntime({
247
- url: config.url,
248
- cssUrl: config.cssUrl
249
- })
304
+ // Runtime mode (foundation URL in site.yml)
305
+ return initRuntime({ url: config.url, cssUrl: config.cssUrl })
250
306
  } else {
251
- // Bundled mode: await the foundation and styles imports
307
+ // Bundled mode - foundation included in build
252
308
  const [foundationModule] = await Promise.all([foundation, styles])
253
309
  return initRuntime(foundationModule)
254
310
  }