Skip to main content

lumio build

Build the extension bundle for deployment. Produces optimized client bundles for each surface and a source archive.

Usage

lumio build [--outdir <path>]

What it produces

After a successful build, the dist/ directory (or custom --outdir) contains per-target bundles and an optional assets/ directory for referenced static files:

dist/
├── editor.js <- Editor surface bundle
├── layer.js <- Layer surface bundle
├── styles.css <- Combined CSS (Tailwind or plain)
├── assets/ <- Static assets referenced by components
│ ├── logo-a1b2c3.png
│ ├── font-d4e5f6.woff2
│ └── animation-g7h8i9.lottie
├── server/ <- Only if server: true
│ └── functions.[hash].js <- Server bundle (ESM)
└── source.tar.gz <- Source archive (required by review process)

Asset handling

Images, fonts, videos, and other static files imported in your code are automatically copied to assets/ with a content hash in the filename. esbuild handles this via file loaders:

File typeOutput pattern
.png, .jpg, .gif, .svg, .webp, .avif, .icoassets/[name]-[hash].[ext]
.woff, .woff2, .ttf, .otf, .eotassets/[name]-[hash].[ext]
.mp4, .webm, .ogg, .mp3, .wavassets/[name]-[hash].[ext]
.json, .lottieassets/[name]-[hash].[ext]

Import assets in your components and the bundler resolves the correct URL at runtime:

import logoUrl from "./assets/logo.png";

export default function Layer() {
return <img src={logoUrl} alt="Logo" />;
}

Example

lumio build
Building Sports Scoreboard v1.2.0...

editor 525 KB (153 KB gzipped)
layer 312 KB (98 KB gzipped)
server 44 KB

source.tar.gz assembled

Build complete → dist/

Options

FlagDescription
--outdir <path>Output directory (default: dist)
--no-sourceSkip generating source.tar.gz (not recommended)

CSS and Styling

lumio build supports three styling approaches. You choose during lumio init, but can switch at any time.

If src/globals.css contains @import "tailwindcss", the build compiles it via the Tailwind CLI before bundling. Use any Tailwind utility classes in your components:

export default function Layer() {
return (
<div className="flex items-center gap-2 bg-black/80 rounded-lg p-4">
<span className="text-white text-sm font-medium">Hello</span>
</div>
);
}

Requires tailwindcss as a dev dependency (npm add -D tailwindcss@^4.3).

Plain CSS

Create src/globals.css (or src/style.css) with regular CSS. The file is copied to dist/styles.css:

.my-widget {
background: rgba(0, 0, 0, 0.8);
border-radius: 8px;
padding: 16px;
}

Import it in your component: import "./globals.css";

Inline styles

No CSS files needed. Style directly via React style props:

export default function Layer() {
return <div style={{ background: "rgba(0,0,0,0.8)", padding: 16 }}>Hello</div>;
}

Source archive

source.tar.gz contains the full source code of your extension (excluding node_modules and dist). It is uploaded alongside the bundle during lumio deploy and made available to reviewers.

warning

CHANGELOG.md must include an entry for the version being built. If no entry is found for the current version in lumio.config.json, the CLI prints a warning — the build still succeeds, but release notes will be empty unless you fill them in via the submission wizard.

TypeScript errors

The build fails on TypeScript errors. To check for errors without building:

npx tsc --noEmit

Bundle size limits

PlanMax bundle size per surface
Free10 MB
Pro50 MB

If a surface bundle exceeds the limit, the build fails with an error. Optimize with dynamic imports or reduce dependencies.