Skip to main content

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:

CommandWhat it does
npm run buildBuilds everything: main renderer, all templates, all widgets
npm run build:cleanDeletes dist/ first, then builds everything
npm run build:templatesBuilds only the templates (skips main renderer and widgets)
npm run build:template --template=my-cool-invoiceBuilds just one template
npm run build:mainBuilds only the main renderer
npm run build:widgetsBuilds only the widgets
npm run build:widget --widget=date-timeBuilds just one widget
npm run typecheckRuns TypeScript type checking without building
npm testRuns 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:

VariableWhat it doesExample
BUILD_TEMPLATES_ONLY=1Only build templatesUsed by npm run build:templates
BUILD_MAIN_ONLY=1Only build the main rendererUsed by npm run build:main
BUILD_WIDGETS_ONLY=1Only build widgetsUsed by npm run build:widgets
TEMPLATE=my-cool-invoiceBuild just this one templateUsed by npm run build:template
WIDGET=date-timeBuild just this one widgetUsed by npm run build:widget
PURGE_OLD_ASSETS=1Delete 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:

  1. Discovers entries by scanning src/templates/ and src/widgets/
  2. Compiles TypeScript through Babel (targeting ES5 for maximum browser support)
  3. Compiles Handlebars templates into JavaScript functions
  4. Extracts CSS into separate files using MiniCssExtractPlugin
  5. Manages versions by computing source digests and auto-bumping semver (see Versioning)
  6. Generates manifests so the main renderer knows where to find template assets
  7. 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