uniweb 0.10.2 → 0.10.5
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/README.md +3 -3
- package/package.json +7 -7
- package/partials/agents.md +26 -1
- package/src/commands/build.js +44 -3
- package/src/commands/deploy.js +981 -164
- package/src/commands/handoff.js +1 -1
- package/src/commands/invite.js +2 -2
- package/src/framework-index.json +22 -11
- package/src/index.js +3 -2
- package/src/utils/config.js +1 -1
- package/templates/foundation/package.json.hbs +2 -2
- package/templates/site/package.json.hbs +2 -2
package/README.md
CHANGED
|
@@ -257,7 +257,7 @@ You can delete the `foundation/` folder entirely and point your site at a publis
|
|
|
257
257
|
|
|
258
258
|
_Site-first_ — You're building a website. The foundation is your component library, co-developed with the site. This is the common case.
|
|
259
259
|
|
|
260
|
-
_Foundation-first_ — You're building a component system. The site is a test harness with sample content. The real sites live elsewhere—other repositories, other teams, or managed on [uniweb.app](https://uniweb.app). Use `uniweb add site` to add multiple test sites exercising a shared foundation.
|
|
260
|
+
_Foundation-first_ — You're building a component system. The site is a test harness with sample content. The real sites live elsewhere—other repositories, other teams, or managed on [hub.uniweb.app](https://hub.uniweb.app). Use `uniweb add site` to add multiple test sites exercising a shared foundation.
|
|
261
261
|
|
|
262
262
|
## Growing Your Project
|
|
263
263
|
|
|
@@ -299,11 +299,11 @@ The structure you start with scales without rewrites:
|
|
|
299
299
|
|
|
300
300
|
1. **Single project** — One site, one foundation. Develop and deploy together. Most projects stay here.
|
|
301
301
|
|
|
302
|
-
2. **Published foundation** — Release your foundation as an npm package or to [uniweb.app](https://uniweb.app). Other sites can use it without copying code.
|
|
302
|
+
2. **Published foundation** — Release your foundation as an npm package or to [hub.uniweb.app](https://hub.uniweb.app). Other sites can use it without copying code.
|
|
303
303
|
|
|
304
304
|
3. **Multiple sites** — Several sites share one foundation. Update components once, every site benefits.
|
|
305
305
|
|
|
306
|
-
4. **Platform-managed sites** — Sites built on [uniweb.app](https://uniweb.app) with visual editing tools can use your foundation. You develop components locally; content teams work in the browser.
|
|
306
|
+
4. **Platform-managed sites** — Sites built on [hub.uniweb.app](https://hub.uniweb.app) with visual editing tools can use your foundation. You develop components locally; content teams work in the browser.
|
|
307
307
|
|
|
308
308
|
Start with local files deployed anywhere. The same foundation works across all these scenarios.
|
|
309
309
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uniweb",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.5",
|
|
4
4
|
"description": "Create structured Vite + React sites with content/code separation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -41,14 +41,14 @@
|
|
|
41
41
|
"js-yaml": "^4.1.0",
|
|
42
42
|
"prompts": "^2.4.2",
|
|
43
43
|
"tar": "^7.0.0",
|
|
44
|
-
"@uniweb/core": "0.7.
|
|
45
|
-
"@uniweb/
|
|
46
|
-
"@uniweb/
|
|
44
|
+
"@uniweb/core": "0.7.3",
|
|
45
|
+
"@uniweb/kit": "0.9.3",
|
|
46
|
+
"@uniweb/runtime": "0.8.4"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
|
-
"@uniweb/build": "0.
|
|
50
|
-
"@uniweb/
|
|
51
|
-
"@uniweb/
|
|
49
|
+
"@uniweb/build": "0.11.2",
|
|
50
|
+
"@uniweb/semantic-parser": "1.1.11",
|
|
51
|
+
"@uniweb/content-reader": "1.1.5"
|
|
52
52
|
},
|
|
53
53
|
"peerDependenciesMeta": {
|
|
54
54
|
"@uniweb/build": {
|
package/partials/agents.md
CHANGED
|
@@ -417,6 +417,31 @@ Access: `content.snippets[0]` → `{ language: 'jsx', code: 'function Hello() {.
|
|
|
417
417
|
|
|
418
418
|
Both appear in `content.sequence` for document-order rendering. The difference: tagged data blocks are parsed and extracted to `content.data`; code snippets are preserved and collected in `content.snippets`. `<Prose>` handles this automatically — it renders code snippets with syntax highlighting and skips tagged data blocks, which components access separately via `content.data`.
|
|
419
419
|
|
|
420
|
+
### Math (LaTeX)
|
|
421
|
+
|
|
422
|
+
Authors write LaTeX directly in markdown; the browser renders real math natively. The LaTeX is compiled to MathML Core **at build time** — no runtime math library ships to the browser, no CSS from a math package is required.
|
|
423
|
+
|
|
424
|
+
Three forms, matching Pandoc / GitHub / VS Code / Jupyter / Obsidian convention:
|
|
425
|
+
|
|
426
|
+
| Form | Mode | Example |
|
|
427
|
+
|---|---|---|
|
|
428
|
+
| `$x^2$` | Inline | `Let $f(x) = ax + b$ be a function.` |
|
|
429
|
+
| `$$x^2$$` | Display (block when on its own line, inline display mid-paragraph) | `$$\sum_{i=1}^n i$$` |
|
|
430
|
+
| ` ```math ` fence | Display (multi-line friendly) | see below |
|
|
431
|
+
| `\$` | Literal `$` | `The price is \$20.` |
|
|
432
|
+
|
|
433
|
+
Multi-line display math uses a `math` code fence:
|
|
434
|
+
|
|
435
|
+
````markdown
|
|
436
|
+
```math
|
|
437
|
+
\int_0^\infty e^{-x^2}\,dx = \frac{\sqrt{\pi}}{2}
|
|
438
|
+
```
|
|
439
|
+
````
|
|
440
|
+
|
|
441
|
+
Disambiguation for `$...$`: a dollar-delimited span counts as math only when the body has no whitespace next to the delimiters *and* the closing `$` is not immediately followed by a digit. So `It costs $5 and $10 total` and `Budget: $200` stay as prose without any escaping, while `Let $f(x) = 5$ be a function` is math. Use `\$` when you need a literal `$` in content where the rules would otherwise trip it up.
|
|
442
|
+
|
|
443
|
+
Math rides through the same content pipeline as everything else — it appears in prerendered HTML, survives `compile('epub')` and `compile('pagedjs')`, and roundtrips cleanly through the editor. Component code needs nothing special; `<Prose>` and `<Text>` already render the MathML that the pipeline embedded.
|
|
444
|
+
|
|
420
445
|
### Composition: Nesting and Embedding
|
|
421
446
|
|
|
422
447
|
Pages are sequences of sections — that's the obvious composition layer. But the framework supports real nesting: sections containing other sections, and sections containing embedded components. And it does this without leaving markdown.
|
|
@@ -891,7 +916,7 @@ fetch:
|
|
|
891
916
|
limit: 3
|
|
892
917
|
```
|
|
893
918
|
|
|
894
|
-
**Lean lists with `deferred:`.** Collections with heavy fields (article bodies, large nested arrays) can declare `deferred: [body]` in `site.yml`. The cascade payload omits those fields; per-record full files are emitted at `/data/<name>/<slug>.json` (
|
|
919
|
+
**Lean lists with `deferred:`.** Collections with heavy fields (article bodies, large nested arrays) can declare `deferred: [body]` in `site.yml`. The cascade payload omits those fields; per-record full files are emitted at `/data/<name>/<slug>.json` (file-based collections — markdown, YAML, or JSON) or fetched from an author-declared `detailUrl:` pattern (API-backed collections). On dynamic-route pages the focused entity's full record is delivered automatically; elsewhere components fetch on demand via the `useEntityDetail` kit hook.
|
|
895
920
|
|
|
896
921
|
**Component-side fetching.** When a component genuinely needs to fetch something on its own (a search box, a "load more" button, a popover that lazy-loads), use the kit hooks (`useFetched`, `useCacheEntry`, `useEntityDetail`). They share the framework's cache and dispatcher with declarative fetches; same-key requests dedupe automatically.
|
|
897
922
|
|
package/src/commands/build.js
CHANGED
|
@@ -11,9 +11,10 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { existsSync, readFileSync } from 'node:fs'
|
|
14
|
-
import { resolve, join } from 'node:path'
|
|
14
|
+
import { resolve, join, dirname } from 'node:path'
|
|
15
15
|
import { spawn } from 'node:child_process'
|
|
16
16
|
import { writeFile, mkdir } from 'node:fs/promises'
|
|
17
|
+
import { createRequire } from 'node:module'
|
|
17
18
|
|
|
18
19
|
// Import build utilities from @uniweb/build
|
|
19
20
|
import {
|
|
@@ -123,6 +124,46 @@ function runCommand(command, args, cwd) {
|
|
|
123
124
|
})
|
|
124
125
|
}
|
|
125
126
|
|
|
127
|
+
/**
|
|
128
|
+
* Resolve the project's local Vite binary.
|
|
129
|
+
*
|
|
130
|
+
* We intentionally do NOT fall back to `npx vite`: npx resolves through npm's
|
|
131
|
+
* global cache, which may hold a stale Vite version (e.g. Vite 5 ignores
|
|
132
|
+
* lib.fileName for CSS and always emits style.css). Using the project's local
|
|
133
|
+
* Vite guarantees the version declared in package.json is the one that runs.
|
|
134
|
+
*
|
|
135
|
+
* @param {string} projectDir
|
|
136
|
+
* @returns {string} Absolute path to the vite CLI entry
|
|
137
|
+
*/
|
|
138
|
+
function resolveLocalVite(projectDir) {
|
|
139
|
+
const require = createRequire(join(projectDir, 'package.json'))
|
|
140
|
+
let pkgJsonPath
|
|
141
|
+
try {
|
|
142
|
+
pkgJsonPath = require.resolve('vite/package.json')
|
|
143
|
+
} catch {
|
|
144
|
+
throw new Error(
|
|
145
|
+
`Vite is not installed in ${projectDir}.\n` +
|
|
146
|
+
`Run \`pnpm install\` (or npm/yarn install) in the project before building.`
|
|
147
|
+
)
|
|
148
|
+
}
|
|
149
|
+
const pkg = JSON.parse(readFileSync(pkgJsonPath, 'utf8'))
|
|
150
|
+
const binRel = typeof pkg.bin === 'string' ? pkg.bin : pkg.bin?.vite
|
|
151
|
+
if (!binRel) {
|
|
152
|
+
throw new Error(`Could not find vite bin entry in ${pkgJsonPath}`)
|
|
153
|
+
}
|
|
154
|
+
return join(dirname(pkgJsonPath), binRel)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Run the project's local Vite with the given args.
|
|
159
|
+
* @param {string} projectDir
|
|
160
|
+
* @param {string[]} args - e.g. ['build']
|
|
161
|
+
*/
|
|
162
|
+
async function runLocalVite(projectDir, args) {
|
|
163
|
+
const viteBin = resolveLocalVite(projectDir)
|
|
164
|
+
await runCommand(process.execPath, [viteBin, ...args], projectDir)
|
|
165
|
+
}
|
|
166
|
+
|
|
126
167
|
/**
|
|
127
168
|
* Build a foundation
|
|
128
169
|
*/
|
|
@@ -158,7 +199,7 @@ async function buildFoundation(projectDir, options = {}) {
|
|
|
158
199
|
|
|
159
200
|
// Check if vite.config.js uses the generated entry
|
|
160
201
|
// For now, just run the standard vite build
|
|
161
|
-
await
|
|
202
|
+
await runLocalVite(projectDir, ['build'])
|
|
162
203
|
|
|
163
204
|
// Vite's foundation plugin generates dist/meta/schema.json
|
|
164
205
|
// and processes preview images during the build.
|
|
@@ -351,7 +392,7 @@ async function buildSite(projectDir, options = {}) {
|
|
|
351
392
|
info('Building site...')
|
|
352
393
|
|
|
353
394
|
// Run vite build for sites
|
|
354
|
-
await
|
|
395
|
+
await runLocalVite(projectDir, ['build'])
|
|
355
396
|
|
|
356
397
|
success('Site build complete')
|
|
357
398
|
|