@uniweb/runtime 0.2.6 → 0.2.7

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 +1 -1
  2. package/src/index.jsx +65 -9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniweb/runtime",
3
- "version": "0.2.6",
3
+ "version": "0.2.7",
4
4
  "description": "Minimal runtime for loading Uniweb foundations",
5
5
  "type": "module",
6
6
  "exports": {
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
@@ -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
  }