@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 +2 -2
- package/src/components/Layout.jsx +14 -12
- package/src/index.jsx +68 -12
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uniweb/runtime",
|
|
3
|
-
"version": "0.2.
|
|
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.
|
|
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
|
|
15
|
+
* Foundations can provide a custom Layout via src/runtime.js:
|
|
16
16
|
*
|
|
17
17
|
* ```jsx
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
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
|
|
233
|
-
*
|
|
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
|
-
//
|
|
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
|
|
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
|
|
307
|
+
// Bundled mode - foundation included in build
|
|
252
308
|
const [foundationModule] = await Promise.all([foundation, styles])
|
|
253
309
|
return initRuntime(foundationModule)
|
|
254
310
|
}
|