Canopy is a JS package that makes it easy to build applications that:
- interop with Splinter
- look and feel like they are part of suite.
A Sapling is a web application using Canopy. It will be served from a Canopy Daemon (or Splinter Daemon itself, this is still not set in stone).
...the cat leaped upon [the mouse] and made an end of her. And that is the way of the world.
- Cat and Mouse in Partnership, The Brother's Grimm.
One of the biggest challenges when concepualizing Canopy were these conflicting ideas:
- We wanted the front-ends to run in relative isolation.
- We wanted to build a bridge between Saplings.
- We wanted developers building Canopy Saplings to have a lot of freedom to bring whatever front-end technologies they wanted.
We do this with a hybrid-SPA model. That is, when a page's route is manipulated by Canopy, instead of a refreshless SPA-model route change, the page is reloaded ensuring that only the Sapling's code that corresponds to the top-level path is loaded. After the Sapling itself is loaded, that application is free to handle the routing however it sees fit.
This gives us a few benefits of isolation.
- Less overall code is loaded.
- Since each Sapling could be its own standalone application, this limits the number of dependencies that would need to be loaded.
- It prevents multiple copies of DOM frameworks from being shipped on every page load.
- Only one Sapling's code can interact with the Canopy at a time
- A malicious Sapling cannot overwrite primitives
- Slow/poorly optimized Saplings do not impact each other's performance.
This does not make us free to trust all third-party Saplings. A malicious actor could still interact with Canopy in a way that is not perscribed in the API. It does however make it much harder to accidentally disrupt the normal functions of other Saplings.
In order to install Sapling there are only a few fields needed.
These should be included in a sapling.manifest.json
file when submitting a Sapling.
This is the JSON Schema
{
"uri_namespace": "notifier",
"human_name": "Notifier",
"main": {
"filename": "main.js"
"integrity": "sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
},
"icon": "128x128.svg",
"workers": [
{
"filename: "other-sapling-interop.js",
"integrity": "sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC",
"runWithMain": true
},
{
"filename: "third-party-notifier.js",
"integrity": "sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC",
"runWithMain": false
}
]
}
There are two API entrypoints
canopyjs/dom
and canopyjs/worker
Worker is a slim version of DOM with a minimal API that makes it possible to interact with Canopy without your whole presentation application being loaded
const canopy = new Canopy({
rootId: "canopy-container",
sidebarId: "canopy-nav",
initialSidebarVisible: true
})
canopy.notify("Something")
canopy.saplings
canopy.user
canopy.setSideNavVisible(false)