Skip to content

Commit edd7298

Browse files
authored
Merge pull request #758 from ethersphere/mutable-content
Manifest and Routing Pages
2 parents f0ceb03 + bc2c1ed commit edd7298

File tree

9 files changed

+1354
-41
lines changed

9 files changed

+1354
-41
lines changed

docs/develop/dynamic-content.md

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
---
2+
title: Dynamic Content
3+
id: dynamic-content
4+
sidebar_label: Dynamic Content
5+
---
6+
7+
:::warning
8+
Under construction, set for major revisions to incorporate content from manifests, rout, and host your website pages
9+
:::
10+
11+
12+
## Feeds for Dynamic Content
13+
14+
:::info
15+
Although all data on Swarm is immutable, feeds provide an updatable reference that lets you simulate dynamic content. A feed is an append‑only sequence of updates that always resolves to its latest entry through a stable feed manifest.
16+
:::
17+
18+
:::tip
19+
If you are not familiar with feeds, read:
20+
- Bee docs: /docs/develop/tools-and-features/feeds/
21+
- Bee-JS docs: https://bee-js.ethswarm.org/docs/soc-and-feeds/
22+
:::
23+
24+
Single‑page applications (SPAs) deployed on Swarm work best when their static assets can be updated independently. Instead of reuploading the entire site when one file changes, you can create a separate feed manifest for each asset. Each asset feed provides a stable URL that always resolves to the latest version of that file.
25+
26+
## Why Use Per‑Asset Feeds
27+
28+
- Each React/Vite build artifact (HTML, JS, CSS, images) becomes individually updatable.
29+
- Every asset has a dedicated feed manifest with its own stable Swarm URL.
30+
- Updating a single file only updates its feed; the rest of the site stays untouched.
31+
- This keeps deployments small, fast, and cost‑efficient.
32+
33+
## Architecture Overview
34+
35+
| Asset | Feed Topic | Purpose |
36+
|----------------------|-----------------|-----------------------------|
37+
| Main site bundle | `website` | HTML/JS/CSS entry point |
38+
| CSS theme | `main-css` | Global styling |
39+
| JS bundle | `main-js` | Application logic |
40+
| Images | `img-*` | Media resources |
41+
42+
Each asset has:
43+
- a private key
44+
- a feed topic
45+
- a feed manifest
46+
- a stable Swarm URL (`bzz://<MANIFEST_HASH>/`)
47+
48+
## Generate a Publisher Key
49+
50+
```js
51+
import crypto from "crypto";
52+
import { PrivateKey } from "@ethersphere/bee-js";
53+
54+
const hex = "0x" + crypto.randomBytes(32).toString("hex");
55+
const pk = new PrivateKey(hex);
56+
57+
console.log("Private key:", pk.toHex());
58+
console.log("Address:", pk.publicKey().address().toHex());
59+
```
60+
61+
## Create a Feed for an Asset
62+
63+
```js
64+
import { Bee, PrivateKey, Topic } from "@ethersphere/bee-js";
65+
66+
const bee = new Bee("http://localhost:1633");
67+
const batchId = "<BATCH_ID>";
68+
69+
const pk = new PrivateKey("<ASSET_PRIVATE_KEY>");
70+
const topic = Topic.fromString("main-js");
71+
const owner = pk.publicKey().address();
72+
73+
const writer = bee.makeFeedWriter(topic, pk);
74+
```
75+
76+
## Upload an Asset and Publish a Feed Update
77+
78+
```js
79+
const upload = await bee.uploadFile(batchId, "./dist/assets/index-398a.js");
80+
await writer.upload(batchId, upload.reference);
81+
82+
const manifest = await bee.createFeedManifest(batchId, topic, owner);
83+
console.log("JS Manifest:", manifest.toHex());
84+
```
85+
86+
Stable URL:
87+
88+
```
89+
bzz://<JS_MANIFEST_HASH>/
90+
```
91+
92+
This URL never changes, even when you replace the underlying file.
93+
94+
## Updating an Existing Asset
95+
96+
```js
97+
const nextUpload = await bee.uploadFile(batchId, "./dist/assets/index-new.js");
98+
await writer.upload(batchId, nextUpload.reference);
99+
```
100+
101+
No new manifest is created. The old URL now resolves to the updated file.
102+
103+
## Referencing Asset Feeds in Your SPA
104+
105+
Rather than referencing a static build hash, point your SPA to feed manifests.
106+
107+
Example `index.html`:
108+
109+
```html
110+
<script type="module" src="bzz://<JS_MANIFEST_HASH>/"></script>
111+
<link rel="stylesheet" href="bzz://<CSS_MANIFEST_HASH>/" />
112+
```
113+
114+
Example React image reference:
115+
116+
```jsx
117+
<img src={`bzz://${IMG_MANIFEST_HASH}/`} alt="Hero" />
118+
```
119+
120+
This makes your deployment resilient to Vite’s changing file names, because Swarm fetches the latest version through the feed instead of the literal file path.
121+
122+
## Example Deployment Workflow
123+
124+
1. Build Vite:
125+
```
126+
npm run build
127+
```
128+
129+
2. For each file in `dist/`:
130+
- assign (or reuse) a feed topic
131+
- upload the file
132+
- update its feed
133+
- store the feed manifest hash in a hard‑coded list inside your SPA
134+
135+
3. Rebuild your SPA to reference:
136+
- `bzz://<JS_FEED_MANIFEST>/`
137+
- `bzz://<CSS_FEED_MANIFEST>/`
138+
- `bzz://<IMAGE_FEED_MANIFEST>/`
139+
140+
4. Upload only the *main* SPA entrypoint (often a small static HTML + JS shell) using `swarm-cli feed upload`.
141+
142+
This gives you a fully working dynamic SPA with lightweight incremental updates.
143+
144+
## Summary
145+
146+
- Each build artifact gets its own updatable feed.
147+
- Your SPA uses stable feed manifest URLs instead of build‑hashed filenames.
148+
- Only changed files need to be uploaded.
149+
- This keeps deployments fast while ensuring long‑lived URLs remain valid.
150+
151+
The next section (not included here) expands this into a registry‑based system for large dynamic sites.
152+
153+

docs/develop/host-your-website.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -478,4 +478,5 @@ This works across:
478478
* localhost (with a compatible RPC)
479479
* any ENS-compatible Swarm resolver
480480
481-
You do not need to encode the hash or use any additional tools. `bzz://<hash>` is sufficient.
481+
You do not need to encode the hash or use any additional tools. `bzz://<hash>` is sufficient.
482+

docs/develop/introduction.md

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,31 @@ pagination_next: null
6161
<span class="hub-card__cta">Open guide</span>
6262
</a>
6363
</li>
64+
<li class="hub-card">
65+
<a class="hub-card__link" href="/docs/develop/manifests">
66+
<h3 class="hub-card__title">Manifests</h3>
67+
<p class="hub-card__desc">
68+
Learn about how manifests enable a virtual "file system" on Swarm, and how to manipulate the manifest to re-write virtual paths to add, remove, or move content.
69+
</p>
70+
<span class="hub-card__cta">Open Guide</span>
71+
</a>
72+
</li>
73+
<li class="hub-card">
74+
<a class="hub-card__link" href="/docs/develop/routing">
75+
<h3 class="hub-card__title">Routing</h3>
76+
<p class="hub-card__desc">
77+
Learn about routing on Swarm and the various options at your disposal for approaching website routing.
78+
</p>
79+
<span class="hub-card__cta">Open Guide</span>
80+
</a>
81+
</li>
6482
<!--
6583
<li class="hub-card">
66-
<a class="hub-card__link" href="/docs/develop/updatable-content">
67-
<h3 class="hub-card__title">Publish Updatable Content</h3>
84+
<a class="hub-card__link" href="/docs/develop/dynamic-content">
85+
<h3 class="hub-card__title">Dynamic Content</h3>
6886
<p class="hub-card__desc">
69-
Learn how to host dynamic content on Swarm which can change over time such as a blog or personal website.
87+
Build dynamic sites on Swarm by updating individual assets through feeds —
88+
enabling granular updates, decentralized CDN patterns, and zero-downtime content changes.
7089
</p>
7190
<span class="hub-card__cta">Open guide</span>
7291
</a>

0 commit comments

Comments
 (0)