|
| 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 | + |
0 commit comments