Assets

Widgets may use different external assets such as images (or even audio and video), WebAssembly files, custom resources, and so on. This section shows how to use some of the most common types of assets in a widget.

How assets are handled in WebWriter

When a widget is loaded into WebWriter (by installing a package), WebWriter bundles the package using esbuild and imports the resulting bundle. This means that a widget may include any type of asset that esbuild allows. Bundling is used again when the author saves the explorable, as all widgets are combined into a single, minimal bundle and the bundle source is embedded into the explorable.

JS

JS is the default asset type. It can be the entry point of your widget with "exports": {... "./widgets/my-widget": "./widgets/my-widget.js"} configured in package.json. Any files imported in your entry point are also bundled (this applies recursively) according to normal bundler behavior.

my-widget.js

import MySubComponent from "./mysubcomponent"

More details can be found in the esbuild documentation on JS.

TypeScript

TypeScript (TS) is a strongly typed language building on JS. In WebWriter, TypeScript has first-class support: A TypeScript file can also be an entry point with "exports": {... "./widgets/my-widget": "./widgets/my-widget.ts"}, configured in package.json. The same rules as for JS generally apply. Additionally, if your package includes a tsconfig.json, it is used when bundling.

my-widget.ts

import MySubComponent from "./mysubcomponent"

More details can be found in the esbuild documentation on TypeScript.

JSX/TSX

JSX is a syntax for JS to create React elements with an XML-like syntax. Some component libraries, most prominently React, use this syntax.

More details can be found in the esbuild documentation on JSX.

JSON

JSON can be imported directly, as well. When a JSON file is imported, it is converted into a JS object at build time. This also applies to .jsonld files.

my-widget.js

import config from "./config.json"

This means that you can also import the package’s package.json if you want to reuse metadata you stored there for the widget.

More details can be found in the esbuild documentation on JSON.

CSS

The recommended way to include styles in a widget is to use a CSS-in-JS approach such as lit’s support for styles.

Alternatively, CSS files can be imported from JS/TS. This will generate a CSS bundle that WebWriter will import along with the widget. Note that the CSS will still not affect your component’s shadow DOM, so this is typically not what you want.

import "./mystyle.css"

More details can be found in the esbuild documentation on CSS.

Text

Any text file with the .txt extension can be imported as a string.

import string from './myfile.txt'
console.log(string)

More details can be found in the esbuild documentation on text.

Media: Images, Icons, (Audio, Video)

Media assets can be imported in your JS/TS code. These assets are converted into a Base64-encoded data URI that can be used directly in any place a URI would be used.

The following file extensions are loaded as data URIs:

  • Image: .apng, .jpg, .jpeg, .jfif, .pjpeg, .pjp, .png, .svg, .webp, .bmp, .ico, .cur, .tif, .tiff
  • Audio: .wav, .wave, .mp3, .aac, .aacp, .oga, .flac, .weba
  • Video: .mp4, .webm, .avif, .gif, .mov, .avi, .ogv, .mkv, .opus, .mpeg
  • Font: .woff, .woff2, .ttf, .otf
  • Document: .pdf

Note that binary file types are loaded in Base64 encoding, while text formats such as SVG as loaded directly as text in the Data URI.

import myicon from "./myicon.svg"

@customElement("my-widget")
class MyWidget extends LitElement {
  render() {
    return html`<img src=${myicon}></img>` // if using Shoelace.js, <sl-icon src=${myicon}></sl-icon> also works
  }
}

As shown in the example, this approach is most useful for using multiple small assets such as a set of icons for the widget.

Larger media assets such as most video and audio files are not intended to be part of a widget’s source. Since these assets would be bundled into every explorable that includes the widget, they would massively increase the widget’s size, and slow down both authoring and usage of the explorable.

WebAssembly

WebAssembly is not supported yet.

Other assets

Other types of assets are not directly supported. However, some other types of assets can be supported by adding a build step to your widget’s development. To achieve this, you need to convert/compile the unsupported asset type into one of the supported asset types.