on 8311dcd help sign in
urbit.org/docs/using/web.udon
448 lines 14 kB history raw
1:- :~ navhome/'/docs/'
2 navuptwo/'true'
3 next/'true'
4 sort/'8'
5 title/'Web (Eyre)'
6 ==
7;>
9# Web (Eyre)
11;div(class "row")
12 ;div(class "col-md-8")
14Your urbit runs its own webserver, Eyre, that handles all things HTTP. Here
15we'll cover the features of Eyre that most resemble a traditional web server.
17By default Eyre uses *Tree*. Tree is a simple ui for browsing the contents of
18the filesystem, statically publishing a blog or any kind of content and for
19running single-page apps.
21Tree was built primarily to display both our documentation and the contents of
22`urbit.org`. If you're interested in doing anything complex, it's worth
23checking out the [docs source](https://github.com/urbit/docs) and the
24[urbit.org](https://github.com/urbit/urbit.org) source.
26We ship `tree` as compiled JavaScript on your urbit, but the source lives in its
27own repo [here](https://github.com/urbit/tree).
29 ==
30==
32## Quickstart
34Your urbit runs a web server and can be found locally at
35`http://localhost:8080/` This is the fastest and easiest way
36to find your urbit's web server. Note that the port that a given urbit uses
37might be `8081`, `8082`, or so on if you're running other processes that might
38be occupying `8080`, such as another urbit. Upon the starting of a ship, it will
39print a message telling you which port it's using.
41Your urbit's web server can be accessed remotely at
42`http://your-urbit.urbit.org/`. You'll need to enter a code to access it in this
43way, one that is generated by running the `+code` command in the Dojo.
45_(Make sure you have a desk mounted to unix, as covered in the
46[setup section](/../../using/setup))._
48##### Serving
50The `/web` directory of the `%home` desk is served by default. You can change
51which desk you're serving by using the command `|serve` in the Dojo.
53Let's create a desk for development called `%sandbox`.
55Use `|merge` to create the new desk containing the contents of `%home`:
57```
58~your-urbit:dojo> |merge %home our %sandbox
59```
61And use `|sync` to continuously update based on changes to `%home`:
63~your-urbit:dojo> |sync %home our %sandbox
65Now let's mount it to unix so that we can save files to it:
67```
68~your-urbit:dojo> |mount /=sandbox=
69```
71And now, to switch the desk you're serving from:
73```
74~your-planet:dojo> |serve %sandbox
75```
77##### Hosting files
79To host a file on the web, save the following in `/sandbox/web/test.udon` in your
80ship's pier through unix.
82```
83# Hello
85This is a simple Udon file.
86```
88Our Tree system allows for pages to be designated as children of other pages.
89To do this for any given page, simply make a new folder in the directory that
90contains the page that will be the parent, and give that directory the same
91name. So, the children of a page `/home/web/foo.udon` will live in a directory
92called `/home/web/foo.udon`.
94Let's continue our with our `test.udon` example. Create `/sandbox/web/test/` and
95add two more Udon files in `/sandbox/web/test/daughter.udon`
96`/sandbox/web/test/son.udon`, respectively. Make sure that they contain valid
97Udon. Udon is our markup language, similar to Markdown; check out the guide
98[here](../../tutorials/).
100> NOTE: Due to a bug in Urbit, you may have to create the directory and the file
101 in it in rapid succession using something like `mkdir sandbox/web/test && touch
102 sandbox/web/test/first.md`.
104Now modify `/sandbox/web/test.udon` to list the children using `;list;`:
106```
107# Hello
109This is a simple Udon file.
111;list;
112```
114To view your file rendered using tree:
116```
117http://localhost:8080/test/
118```
120To view your file as raw Udon:
122```
123http://localhost:8080/test.udon
124```
126To view your file as raw `html`:
128```
129http://localhost:8080/test.html
130```
132Now navigate to the "daughter" file that you created:
134```
135http://localhost:8080/test/daughter.udon
136```
138In Urbit, there is no distinction between a directory and a file. So, if you're
139adding files directly from unix, simply `mkdir test` and Urbit will treat the
140file and directory as the same entity.
142You can use this feature to change your homepage at `your-urbit.urbit.org` with
143the page `/home/web.udon`, where `home` is the current mounted desk. By default,
144`web.udon` will display some info about your urbit, but you can customize it to
145your heart's content.
148## Manual
150## `/web`
152This is the equivalent of a `public_html` directory. Your urbit looks in this
153directory to serve content to the world. You can change what desk you're serving from using `|serve`.
155Switch to the `%sandbox` desk:
157```
158|serve %sandbox
159```
161Let's quickly step through the default contents of `web/`:
163- `404.hoon` - The default 404 page.
164- `dojo.hoon` - Page body that loads the `dojo` React module.
165- `lib/css/bootstrap.css` - The Urbit-flavored bootstrap
166- `lib/css/codemirror.css` - Syntax highlighting
167- `lib/css/fonts.css` - The Urbit custom fonts
168- `lib/js/hoon.js` - Hoon syntax highlighting
169- `lib/js/sole.js` - `dojo` operational transformation JS
170- `lib/js/urb.js` - Base Urbit JS library. Handles AJAX and polling.
171- `static.udon` - Sample static file
172- `talk/` - Talk compiled JS / CSS
173- `talk.hoon` - Page body that loads the `talk` React module.
174- `testing.udon` - Guide to writing unit tests in Urbit
175- `tree/` - Tree compiled JS / CSS
176- `tree.hoon` - Page body that loads the `tree` React module.
177- `unmark/` - Used for testing `.udon`.
178- `womb/` - Womb compiled by JS/CSS
179- `womb.hoon` - Used for issuing planets on the test network.
181## Tree
183Tree is a simple publishing tool for files that live on your urbit. You're
184probably reading this file using Tree right now. The main driving use-case for
185Tree has been for us to host our own documentation and the surrounding
186discussion. Tree remains a pretty simple and flexible tool for getting content
187online. It resembles a cross between [Jekyll](https://jekyllrb.com/),
188[Kirby](https://getkirby.com/) and macOS's Finder. We think it's pretty great.
190Tree is also the basic UI for browsing the filesystem. We take it one step
191further and make it possible to write modules (tiny little apps), like Talk and
192Dojo, that can be run directly inside of Tree.
194In the browser Tree is a [React](https://facebook.github.io/react/) /
195[Flux](https://facebook.github.io/react/blog/2014/05/06/flux.html) app that uses
196a slightly modifed version of [Bootstrap](http://getbootstrap.com/). On your
197Urbit Tree is a renderer that translates data in `%clay`, our filesystem, into
198JSON / JSX that can be read by the client.
200Your urbit comes with a pre-built copy of the tree (as a single `.js` file). If
201you're interested in helping to develop tree or learning about how it works, it
202has its own GitHub repo [here](https://github.com/urbit/tree). We have our own
203fork of Bootstrap, which lives [here](https://github.com/urbit/bootstrap).
205## `/web/pages`
207To render content without the Tree put it in `/web/pages`. Files in this
208directory aren't wrapped by Tree.
210## Publishing files
212Publishing files in Tree is simple. Try dropping a file in `/web` (as covered
213in the Quickstart) and navigating to it.
215The best example of more complicated usage of Tree is covered by the Urbit docs
216themselves. See anything while perusing the docs that you'd like to use
217yourself? The docs are all on GitHub [here](https://github.com/urbit/docs).
219## Frontmatter
221Most `.udon` files begin with some frontmatter, which determines the title and
222other settings for rendering the file correctly. E.g.:
224```
225:- :~ navhome/'/home/'
226 next/'true'
227 sort/'1'
228 title/'Example Frontmatter Title'
229 ==
230;>
231```
233Here are the fields we support:
235##### title
237String. Example: `title/'Tree manual'`.
239This sets the title in the nav or in lists as distinct from the filename.
241##### next
243Boolean. Example: `next/'true'`
245Adds a 'next' link at the bottom of the page that links to the next item as decided by the sort order.
247##### sort
249Integer. Example: `sort/'7'`
251User-defined sort. Indicates the sort order as distinct from alphabetical sort.
252These numbers should not be overlapping.
254##### hide
256Boolean. Example: `hide/'true'`
258Whether or not to hide the item from the tree.
260##### date
262Urbit date. Example: `date/'~2016.2.22'`
264Used for sorting posts by date.
266##### Arbitrary Frontmatter
268Any arbitrary category can be used as long as it's given data of valid types.
269Arbitrary categories can be used with the ones mentioned above. Below is
270valid front matter:
272```
273:- :~ date/~2018.9.12
274 author/~lodleb-ritrul
275 music/'rad'
276 ==
277```
279## Using components
281Tree is built using React with a small library of components that you can add to your pages using [JSX](https://facebook.github.io/jsx/) tags.
283If you don't know anything about JSX that's okay: basically we just give you a few custom HTML tags that you can use to create components on the page.
285For those familiar with React / Flux each JSX tag corresponds to a component in [the source](https://github.com/urbit/tree/tree/master/js/components).
287### `<list>`
289Example: `<list src="/posts" titlesOnly="true" />`
291Creates a list of children at a path. Defaults to the current path.
293Optional properties:
295- `src`: Path to load kids from.
296- `titlesOnly`: Only show the 'title' which is either the filename or the first h1.
297- `sortBy`: Can be `date` if items have a `date` YAML.
298- `className`: Class to be assigned to the container.
300### `<kids>`
302Example: `<kids src="/posts" />`
304Includes all the children at the specified path separated by `<hr>` tags.
306Optional properties:
308- `src`: Path to load kids from.
309- `className`: Class to be assigned to the container.
311### `<toc>`
313Example: `<toc noHeader="true" />`
315Creates a table of contents from the `h1` - `h6` tags on the page.
317Optional properties:
319- `match`: Tag name to match. If you wanted to only match `h2` tags it could be `match="h2"`
320- `noHeader`: By default we add a 'Table of Contents' header to the top. Remove it with `noHeader="true"`.
322## Implementation
324On the frontend Tree is mostly just a standard Flux app: components generate actions that get dispatched to stores which are picked up by components. If you're not familiar with Flux, [this overview](https://facebook.github.io/flux/docs/overview.html) is a good place to start.
326As a file browser Tree does a simple job: it fetches data and keeps a cache of what it has seen. To do this simple job we do three fancy things: `manx` to JSON encoding, the Async component and Modules.
328### `manx` to JSON format
330Since we want to use React to manage our DOM lifecycle we actually transfer the DOM structure of each page as JSON over the wire, and 'reactify' it on the client side.
332On the Urbit side we have a type for html: `++manx`. Our wire format for sending HTML as JSON is really similar to a `++manx`. If you're not interested here's what the json looks like:
334```
335"string" || {gn:"string", ga:{key:"string", [...]}, c:[...]}
336```
338To make this clearer let's look at some HTML and its JSON representation:
340```
341<div class="blue">
342 <h1>Title</h1>
343</div>
344```
346```
347{gn:"div", ga:{className:"blue"}, [
348 {gn:"h1", ga:null, "Title"}
349]}
350```
352To see the mechanics of how this is handled on the frontend, checkout
353`components/Reactify.coffee` in the `urbit/tree` repo.
355### Async component
357Each of our components (even those we fetched from the server) can depend on
358data that may not exist in our stores, so we wrap our components in a
359general-purpose Async component. You can find the component in
360`components/Async.coffee` in the `urbit/tree` repo.
362When we say that we just fetch HTML as JSON it's actually slightly more
363complicated. When we fetch a node in the filesystem we might not want to fetch
364its entire contents. Sometimes we just get the title as a part of a list of
365children, sometimes we might get a snippet (in a list with previews), and
366sometimes we get the whole thing. On the Urbit side these results are provided
367by `ren/tree/json`.
369From the perspective of the frontend we just send queries on a path that obey a
370simple API. To see this in action, here's our `BodyComponent`:
372```
373query {
374 body:'r'
375 name:'t'
376 path:'t'
377 meta:'j'
378 sein:'t'
380```
382Here we're asking for the body, name, path, metadata and parent of the current
383path. When it loads that data gets passed to our component as props.
385### Module basics
387A module is a special component that can kind of 'take over' the page. It can
388change properties of the nav bar as well as load custom scripts / css.
390Talk, for example, looks like this:
392```
393<module nav_title="Talk" nav_no-dpad="" nav_no-sibs="" nav_subnav="talk-station">
394 <script src="/~~/~/at/lib/js/urb.js" />
395 <script src="/talk/main.js" />
396 <link href="/talk/main.css" rel="stylesheet" />
397 <talk />
398</module>
399```
401A module will first download all the scripts and styles that it specifies before
402trying to load any contained components. This means that you can define React
403components in external scripts and a module can be entirely self contained.
404The `<talk>` component isn't a part of Tree — it's loaded first before it's
405executed.
407If you're interested in seeing how a module works you can check out the source
408for Talk [here](https://github.com/urbit/talk). Dojo also ships on your urbit,
409its source is [here](https://github.com/urbit/sole).
411## `urb.js`
413The most basic interface between your browser and your urbit is `urb.js`. This
414small library provides the basic utilities for sending and receiving messages
415from an urbit.
417### `window.urb.appl`
419Each JSON message sent to your urbit needs an app endpoint. Can be set as a
420global `window.urb.appl` or set on a per-request basis in the payload to
421`send()`.
423### `window.urb.oryx`
425CSRF token. Written to the page by Eyre, our webserver, when logged in.
426Required part of any authenticated request and included by default.
428### `window.urb.req(method,url,params,json,cb)`
430Our basic request wrapper. You can see here how a request needs to be packaged
431to be properly understood by your urbit.
433### `window.urb.subscribe({path:"string"})`
435Subscribe to an endpoint. Subscription data is returned through the continuous
436long poll.
438### `window.urb.unsubscribe({path:"string"})`
440Close subscription on specified path.
442### `window.urb.poll()`
444Mechanics of the continuous long poll. Used mostly internally.
446### `window.urb.util`
448Library of utility and helper functions.