Build System Overview
Ceres uses webpack to turn your template source files into browser-ready bundles. This page explains how the build works, what commands you can run, and what comes out the other end.
What the build does
You write these files:
src/templates/my-cool-invoice/
index.ts
template.hbs
styles.css
The build turns them into these files:
dist/templates/my-cool-invoice/
1.0.0/
bundle.js # Compiled template + widget code
bundle.css # All styles combined
manifest.json # Version and file references
manifest.json # Root manifest pointing to the latest version
The template's Handlebars file gets pre-compiled into JavaScript. The CSS gets extracted and minified. Everything gets a version number.
npm scripts
Here are the commands you will use:
| Command | What it does |
|---|---|
npm run build | Builds everything: main renderer, all templates, all widgets |
npm run build:clean | Deletes dist/ first, then builds everything |
npm run build:templates | Builds only the templates (skips main renderer and widgets) |
npm run build:template --template=my-cool-invoice | Builds just one template |
npm run build:main | Builds only the main renderer |
npm run build:widgets | Builds only the widgets |
npm run build:widget --widget=date-time | Builds just one widget |
npm run typecheck | Runs TypeScript type checking without building |
npm test | Runs Jest tests |
Environment flags
The build system uses environment variables to control what gets built. You do not usually need to set these yourself since the npm scripts handle it. But here they are for reference:
| Variable | What it does | Example |
|---|---|---|
BUILD_TEMPLATES_ONLY=1 | Only build templates | Used by npm run build:templates |
BUILD_MAIN_ONLY=1 | Only build the main renderer | Used by npm run build:main |
BUILD_WIDGETS_ONLY=1 | Only build widgets | Used by npm run build:widgets |
TEMPLATE=my-cool-invoice | Build just this one template | Used by npm run build:template |
WIDGET=date-time | Build just this one widget | Used by npm run build:widget |
PURGE_OLD_ASSETS=1 | Delete old version folders from dist/ | Optional cleanup |
How entry points are discovered
The build system does not have a hardcoded list of templates. It finds them automatically.
For templates, it scans src/templates/ for folders that contain an index.ts file:
src/templates/
basic-invoice-example/
index.ts <-- found! entry point: templates/basic-invoice-example/bundle
tsn-custom/
index.ts <-- found! entry point: templates/tsn-custom/bundle
For widgets, it does the same thing with src/widgets/:
src/widgets/
date-time/
index.ts <-- found! entry point: widgets/date-time/bundle
invoice-status/
index.ts <-- found!
This means you do not need to edit the webpack config when you add a new template or widget. Just create a folder with an index.ts and it will be picked up automatically.
What the webpack config does
The webpack config (webpack.config.js) is a big file (686 lines) but it does a few clear things:
- Discovers entries by scanning
src/templates/andsrc/widgets/ - Compiles TypeScript through Babel (targeting ES5 for maximum browser support)
- Compiles Handlebars templates into JavaScript functions
- Extracts CSS into separate files using MiniCssExtractPlugin
- Manages versions by computing source digests and auto-bumping semver (see Versioning)
- Generates manifests so the main renderer knows where to find template assets
- Copies thumbnails from source to the versioned output folder
Output structure
After a full build, dist/ looks like this:
dist/
index.html # Entry page
main-manifest.json # Points to the renderer bundle
main-renderer/
renderer.a1b2c3d4.js # Main renderer (content-hashed)
templates/
basic-invoice-example/
manifest.json # Root manifest (latest version)
1.0.101/
bundle.js # Template code
bundle.css # Template styles
manifest.json # Version-specific manifest
thumbnail.png # Preview image
widgets/
invoice-status/
bundle.1.0.3.js # Widget code (version in filename)
bundle.1.0.3.css # Widget styles
manifest.json # Widget manifest
widgets-manifest.json # Summary of all widgets