Assets in Bonito represent external resources like JavaScript libraries, CSS files, images, and other files. They handle loading, bundling, and serving these resources efficiently across different deployment ways (Server/Plotpane/Notebooks/Static Site/Documenter).
Assets can reference local files or remote URLs and are automatically served with the appropriate URLs:
using Bonito
# Load a local image
dashi_logo = Asset(joinpath(@__DIR__, "dashi.png"))
# Create an app that displays the image
app = App() do
# Use CSS class selector to style child images of this specific container
img_styles = Styles(CSS(".asset-container > img", "width" => "400px"))
DOM.div(
img_styles,
DOM.div(
DOM.h2("Asset Example"),
DOM.p("Assets render automatically as the appropriate DOM element:"),
dashi_logo, # Automatically becomes DOM.img(src=url_to_asset)
DOM.p("Or use assets as src attributes for more control:"),
DOM.img(src=dashi_logo; width="400px"); # Asset URL is inserted as src
class="asset-container"
)
)
endAssets render automatically as the appropriate DOM element:

Or use assets as src attributes for more control:

JavaScript assets come in two flavors: ES6 modules and traditional scripts.
ES6Module(path)Create an ES6 module asset that will be bundled using Deno.
ES6 modules are automatically bundled with their dependencies when first loaded. Interpolating an ES6Module in JavaScript code returns a Promise that resolves to the module's exports.
Example
THREE = ES6Module("https://unpkg.com/three@0.136.0/build/three.js")
js"""
$(THREE).then(module => {
// Use the module
const scene = new module.Scene();
})
"""Rebundling
Bonito tracks the timestamp of the main module file and will automatically rebundle if it detects changes. However, changes to imported/included files (e.g., Session.js imported by Bonito.js) are not tracked.
To force a rebundle when you've modified an included file, delete the bundle file:
mod = ES6Module("path/to/module.js")
rm(mod.bundle_file) # Bonito will rebundle on next useFor Bonito's internal JavaScript:
rm(Bonito.BonitoLib.bundle_file)You can also use the convenient CDN helper (uses esm.sh):
THREE = CDNSource("three"; version="0.137.5")For traditional JavaScript libraries that expose global variables (like jQuery, ACE editor, etc.):
# The Asset automatically infers the global name from the filename
ace = Asset("https://cdn.jsdelivr.net/ace-builds/src-min/ace.js")
# name is automatically set to "ace"
# Interpolating returns a Promise that resolves with the global object
js"""
$(ace).then(ace => {
const editor = ace.edit(element);
})
"""
# Override the global name if needed
custom = Asset("https://example.com/library.js"; name="MyLib")Non-JavaScript assets are loaded as raw bytes when interpolated into javascript:
image = Asset("path/to/image.png")
js"""
$(image).then(bytes => {
// bytes is a Uint8Array
})
"""Full ES6Module example creating a THREEJS visualization:
# Javascript & CSS dependencies can be declared locally and
# freely interpolated in the DOM / js string, and will make sure it loads
# Note, that they will be a `Promise` though, so to use them you need to call `module.then(module=> ...)`.
const THREE = ES6Module("https://cdn.esm.sh/v66/three@0.136/es2021/three.js")
app = App() do session, request
width = 500; height = 500
dom = DOM.div(width = width, height = height)
Bonito.onload(session, dom, js"""
function (container){
$(THREE).then(THREE=> {
var renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize($width, $height);
renderer.setClearColor("#ffffff");
container.appendChild(renderer.domElement);
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, $width / $height, 0.1, 1000);
camera.position.z = 4;
var ambientLight = new THREE.AmbientLight(0xcccccc, 0.4);
scene.add(ambientLight);
var pointLight = new THREE.PointLight(0xffffff, 0.8);
camera.add(pointLight);
scene.add(camera);
var geometry = new THREE.SphereGeometry(1.0, 32, 32);
var material = new THREE.MeshPhongMaterial({color: 0xffff00});
var sphere = new THREE.Mesh(geometry, material);
scene.add(sphere);
renderer.render(scene, camera);
})
}
""")
return dom
end