Skip to content

Static Assets

Vantris handles images, fonts, media, and other files as first-class assets — importing one resolves it to a (hashed, in the build) URL, and the behaviour is identical in dev and build.

Importing an asset

Import a file from JavaScript and you get its URL:

ts
import logoUrl from "./logo.svg";

const img = document.createElement("img");
img.src = logoUrl; // "/src/logo.svg" in dev, "/assets/logo-a1b2c3.svg" in build

In a build, the file is copied to outDir with a content hash, and the import resolves to an absolute URL derived from base. In dev, it resolves to the served path. Either way, your code is the same.

Supported asset types

CategoryExtensionsImport resolves to
Imagespng, jpg, jpeg, gif, svg, webp, avif, ico, bmpURL
Fontswoff, woff2, ttf, otf, eotURL
Mediamp4, webm, mp3, wav, … (audio/video)URL
Otherwasm, txtURL
Datajsonparsed data

JSON

json is special — it's imported as data, not a URL:

ts
import config from "./config.json";
console.log(config.version);

// Named imports work too (fields are individually exported):
import { version } from "./config.json";

WebAssembly & text

wasm and txt resolve to a URL, so you fetch/instantiate them yourself:

ts
import wasmUrl from "./add.wasm";
const { instance } = await WebAssembly.instantiateStreaming(fetch(wasmUrl));

import shaderUrl from "./shader.txt";
const source = await fetch(shaderUrl).then((r) => r.text());

Assets in CSS and HTML

  • CSSurl("./bg.png") is rewritten and hashed. See CSS.
  • HTMLsrc/href in <link>/<img>/<script> that point into rootDir are hashed and rewritten. Public and external references are left untouched. See Building → HTML processing.

The public/ directory

Files in publicDir (default ./public) are the escape hatch for assets you don't import — files that need a stable, predictable URL:

  • Served at the root during dev: public/favicon.svg/favicon.svg.
  • Copied verbatim into outDir on build — never hashed, never transformed.

Reference them with an absolute path from the root, not a relative import:

html
<link rel="icon" href="/favicon.svg" />
ts
// public assets are referenced by URL, not imported
const iconUrl = "/favicon.svg";

Use public/ for: favicon, robots.txt, manifest.webmanifest, files referenced by a third party, or anything whose URL must not change between builds. Everything else — assets you import — should live under rootDir so they're hashed and cache-busted.

public/ vs. imported assets

Imported (import x from "./x.png")public/x.png
Locationanywhere under rootDirpublic/ only
Hashed in build❌ (verbatim)
Referenced bythe import's return valuea fixed absolute URL
Cache-bustingautomaticnone — you manage it
Use forapp assetsfavicons, robots.txt, fixed URLs

The base path

Imported asset URLs are prefixed with base in the build, so they resolve correctly when the app is deployed under a sub-path or served from a CDN. Public assets, referenced by absolute path, resolve against the same base at serve time. See Building → base.

Type declarations

vantris/client declares these asset modules so TypeScript types the imports (e.g. import logo from "./logo.svg" as string). Add it to your tsconfig types. See Client Types.

Released under the MIT License.