Tutorial: 5-minute blog
Last edited: April 18, 2019
Time commitment: about an hour.
The simplest full app you can make in Hyperfiddle is a blog. Here is the final result, which has:
- Three Datomic queries
- One Reagent view
It takes me about 300 seconds to run through this demo. The equivalent as a proper Clojure project boilerplate involves the following:
- build tools,
- setup Datomic,
- code http web service,
- code browser entrypoint,
- code routing,
- code client/server data sync,
- code asynchronous http requests,
- code error handling
- code node server rendering,
- deal with deploys,
Go to http://tank.hyperfiddle.net, login, and make your first fiddle
Please namespace your fiddles with your username since the tank is a shared environment.
If it's read-only, you aren't logged in.
Click stage to redirect to your newly created fiddle
- All fiddles are URL addressable, the fiddle/ident is in the URL.
- We provide a default query for you to modify.
- Note your fiddle edits are in the IDE stage.
- Stage state is backed by browser localstorage until you click transact.
- Stage state syncs across tabs and sessions.
Change the :fiddle/query: add
:dustingetz.post/title to the where clause.
- Press alt-enter to refresh
- By convention, all schema attributes should be namespaced to the responsible maintainer.
- This tutorial is coded against :dustingetz.post schema because it has some existing sample data.
Forms and tables are automatically driven by your query and Datomic schema
The tooltip shows us that :published-date is an :instant, which is why the default cell renderer is a datepicker.
The schema editor is linked, follow the link.
- The dustingetz.post schema is already installed into $.
- You can make new attributes here (please namespace with username)
- No need to make new attributes for this tutorial.
- Press the browser back button to go back to the query.
- Hyperfiddle doesn't break the web. Links work, back button works.
Specify the pull columns, these drive the table
- The table has three columns because the pull specifies three columns.
- Table cell widget types are reflected from Datomic schema (you can inspect schema in the label tooltip).
- Nobody else can see your changes until you transact them.
- The stage is backed by browser localstorage.
- You can edit the stage by hand, including clear it out or paste any valid Datomic transaction.
- Copy/paste this for your renderer.
- Auto-indent a codemirror with
- To restore the default renderer, you can delete your :fiddle/renderer and then blur the field.
ctxis in lexical scope. This managed value contains Datomic metadata (e.g. schema, query)
hypercrud.browser.context/datareturns the result subtree value for "where I am focused".
- In the happy path you only ever call context/data
(ns (:require ...))yet, so you must fully qualify all namespaces e.g.
- Auto-indent a codemirror with
[e]on line 6 corresponds with the shape of the tupled Datomic resultset.
- Don't forget to turn your date into a string, and handle nil dates!
:fiddle/cljs-ns lets us defn
- All fiddles have a ClojureScript namespace available inside your :fiddle/renderer as
- This is available at the "cljs" tab
- No :require or deps.edn yet.
EDN view lets us see the Datomic resultset directly.
- This disables any custom renderer to see what's really going on
- Useful if the renderer breaks and for administration
- Links in Hyperfiddle are like links in HTML.
- Hyperfiddle has three kinds of link:
- forms (buttons)
We want to link to an individual post
- The first thing we need is an anchor-attribute. This is the value which will appear in the URL.
- You generally don't want :db/id in the URL and :db/id is a very bad attribute for links since it occurs everywhere!
- Change the query to add :dustingetz.post/slug, which is :db.unique/identity
- This stable identity is suitable for URLs
Make a link using ::slug as the anchor-attribute
- Navigate to the link editor
- Make a new link at path :dustingetz.post/slug
Two things happened
- It's invalid because we haven't set a link target-fiddle yet
- The link showed up in two places!
That will make sense in a minute, first lets make it valid.
In the link editor, create the target-fiddle
Don't forget to recompute with
Now the links are working
Hover a link to see how it evaluated
:db/id has canonicalized to use the slug
- Hyperfiddle understands your intent to link to an entity
- Links appear anywhere they are valid
Links appear anywhere they are valid ("identity fallback")
- If ::slug is not set or pulled, it will fallback to whatever other identity is available (:db/id in this case)
- Manually stage the following transaction to see this in action
- The link must always work if it is possible to satisfy the dependency!
A real life example of :db/id fallback is the Hyperfiddle docs app
- No tutorial action for you here, just an aside.
- Messy data happens. How are you gonna fix the data if the link is broken?
- http://www2.hyperfiddle.net/:docs!index/ (data mode)
Remove :db/id from your pulls if you don't want this behavior.
- You only need one way to identify an entity
- Hyperfiddle will figure it out and use the best one
- We support :db.unique/identity, :db/ident, and :db/id
Whack the staging area to make :automatic-crud-links happy again.
Navigate your new ::view-post link
- The URL is "ednish" encoded.
- This is not quite perfectly reversible to EDN, but close enough.
- (There are only so many nice characters available in the URL spec)
- PRs accepted! https://github.com/hyperfiddle/hyperfiddle/blob/master/src/contrib/ednish.cljc
Set an explicit pull
- Explicit pulls are used to render a blank form and you should set them.
*is generally an anti-pattern in Hyperfiddle (it contains no information about data shape)
- It's good for exploration though
Manually edit the URL to a tempid and see a blank form
- Type into the form, it works and stages datoms using your tempid
- Note that the transaction emitted by Hyperfiddle does not use the ::slug as a lookup ref
- Because :db.unique/identity attributes are not valid lookup-refs until they are transacted
- Whack this stage, don't transact it unless you want to
Why does this example use :fiddle/markdown in userland?
- :fiddle/markdown is from the hyperfiddle schema on the right hand side
- We are setting ourselves up to do something clever in the future
- If you are curious, see: http://www.dustingetz.com/:importance-of-namespaced-keywords/
- For now just ignore it. Reuse existing schema if the semantics make sense for what you want to do.
Toggle back to :view and render the post markdown
Press back button to go back to the blog index and wire up the links in the :fiddle/renderer
- The Context API is responsible for interpreting your resultset in terms of the Datomic :find spec
- (E.g. FindRel / FindColl / FindTuple / FindScalar, :db.cardinality/many, :db.unique/identity)
- It can individually identify each position in a table/form in an attribute/identity centric way
Tighten up the CSS if you want
New blog post button
- Data mode
- Make a new link at :dustingetz.post/slug, with :class
[:hf/new](:link/class is :db.cardinality/many which renders as vector here)
- Make a new fiddle to model the "new post" form
Alt-click any pink-box to drill down (navigate deeper in a new tab)
Specify the pull
Close the tab to go back, and try it out
Transactions: Automatically add today's date to all new blog posts:
2. Wire your txfn by name from the :link/tx-fn
- Your txfn will be called whenever the popover "stage" button is clicked.
- The result is concat'ed with the form
Try it, make sure it works!
You can always look at the stage to see what Datomic transactions were generated.
Transact both stages to save.
- Until you transact, all of our work is still in localstorage, nobody else can see it
- Make sure you transact both stages – your fiddle edits, and your data edits
Production – edit your URL "hyperfiddle.net" to "hyperfiddle.com"
- Prod is server rendered progressive web app
- SSR is happening in AWS Lambda
- Hyperfiddle regularly withstands hackernews traffic, it's hosted all of our web properties for 18 months now
- Prod has a 5min cache window, check the headers in the browser devtool
- Immutable database gives lots of fun opportunities for caching. All XHR requests have a time-basis and are cache-control: immutable
That's almost everything. Topics not covered:
- iframes & picklists
- dependent picklists