Skip to content

Configuration System Overview#

A comprehensive guide to Jac Client's configuration and package management system.

Introduction#

Jac Client uses jac.toml (the standard Jac project configuration file) for all settings. This provides:

  • Single source of truth: All configuration in one place
  • Unified with core Jac: Same config file for all Jac features
  • Version control friendly: Only jac.toml needs to be committed
  • Automatic generation: Build files are generated from configuration

Architecture#

Configuration Flow#

┌─────────────────┐
│   jac.toml      │  ← Source of truth (committed to git)
│  (project root) │
└────────┬────────┘
         │ Loaded by JacClientConfig (wraps core JacConfig)
┌─────────────────┐
│  Merged Config  │  ← Defaults + User config (deep merge)
└────────┬────────┘
         ├─────────────────┬─────────────────┐
         │                 │                 │
         ▼                 ▼                 ▼
┌──────────────┐  ┌──────────────┐  ┌──────────────┐
│ ViteBundler  │  │ npm install  │  │  Other       │
│              │  │              │  │  Components  │
└──────┬───────┘  └──────┬───────┘  └──────┬───────┘
       │                  │                  │
       ▼                  ▼                  ▼
┌──────────────┐  ┌──────────────┐  ┌──────────────┐
│vite.config.js│  │package.json  │  │  Other       │
│(generated)   │  │(generated)   │  │  Generated   │
└──────────────┘  └──────────────┘  └──────────────┘

Key Components#

  1. JacConfig (core jaclang.project.config)
  2. Core configuration class for all Jac projects
  3. Manages jac.toml loading and saving
  4. Handles [dependencies.npm] sections

  5. JacClientConfig (config_loader.jac)

  6. Wraps core JacConfig for client-specific access
  7. Reads from [plugins.client] for vite/ts config
  8. Reads from [dependencies.npm] for packages

  9. ViteBundler (vite_bundler.jac)

  10. Generates vite.config.js from config
  11. Generates package.json from npm dependencies
  12. Handles build and bundling

Configuration File Structure#

Complete jac.toml Structure#

[project]
name = "my-app"
version = "1.0.0"
description = "My Jac application"
entry-point = "main.jac"

# Vite configuration
[plugins.client.vite]
plugins = []
lib_imports = []

[plugins.client.vite.build]
sourcemap = false
minify = "esbuild"

[plugins.client.vite.server]
port = 5173

[plugins.client.vite.resolve]
# Custom resolve options

# Debug mode (enabled by default)
[plugins.client]
debug = true  # Set to false to disable raw error output

# TypeScript configuration (optional)
[plugins.client.ts.compilerOptions]
strict = true
target = "ES2020"

# npm dependencies
[dependencies.npm]
lodash = "^4.17.21"

[dependencies.npm.dev]
sass = "^1.77.8"

Section Overview#

Section Purpose Documentation
[project] Project metadata Core Jac config
[serve] Server and routing configuration See below
[plugins.client] Client plugin settings (debug mode) See below
[plugins.client.vite] Vite build configuration Custom Configuration
[plugins.client.ts] tsconfig.json customization Custom Configuration
[dependencies.npm] npm runtime dependencies Package Management
[dependencies.npm.dev] npm dev dependencies Package Management

Server Configuration ([serve])#

The [serve] section configures how jac start handles routing for client-side applications:

[serve]
cl_route_prefix = "cl"      # URL prefix for client apps (default: "cl")
base_route_app = "app"      # Client app to serve at root "/" (default: none)
Option Type Default Description
cl_route_prefix string "cl" The URL path prefix for client-side apps. Apps are served at /<prefix>/<app_name>.
base_route_app string "" Name of a client app to serve at the root / path. When set, visiting / renders this app instead of the API info page.

Example: Custom route prefix

[serve]
cl_route_prefix = "pages"

With this config, client apps are accessed at /pages/MyApp instead of /cl/MyApp.

Example: Serve app at root

[serve]
base_route_app = "app"

With this config, visiting / renders the app client function directly, making it the default landing page.

Debug Mode ([plugins.client])#

The [plugins.client] section configures debug settings for the client plugin:

[plugins.client]
debug = true      # Enable/disable debug mode (default: true)
Option Type Default Description
debug bool true When enabled, raw error output is displayed for easier debugging. Set to false for cleaner production error messages.

Debug mode can also be controlled via environment variable:

  • JAC_DEBUG=1 or JAC_DEBUG=true enables debug mode regardless of config

Configuration Loading#

Default Configuration#

The system starts with sensible defaults.

Default Vite Config Structure:

[plugins.client.vite]
plugins = []
lib_imports = []

[plugins.client.vite.build]
# Default build options

[plugins.client.vite.server]
# Default server options

[plugins.client.vite.resolve.alias]
"@jac/runtime" = "compiled/client_runtime.js"
"@jac-client/assets" = "compiled/assets"

Deep Merge Strategy#

User configuration is merged with defaults using deep merge:

  • Top-level keys: User config overrides defaults
  • Nested objects: Deep merged (user values override defaults)
  • Arrays: User arrays replace defaults (no merging)
  • Missing keys: Defaults are used

Package Management#

Configuration-First Package Management#

Packages are managed through jac.toml:

[dependencies.npm]
lodash = "^4.17.21"

[dependencies.npm.dev]
sass = "^1.77.8"

Package Lifecycle#

  1. Add Package: jac add --npm <package>
  2. Updates jac.toml
  3. Regenerates package.json
  4. Runs npm install

  5. Install All Packages: jac add --npm (no package name)

  6. Reads all packages from jac.toml
  7. Regenerates package.json
  8. Runs npm install

  9. Remove Package: jac remove --npm <package>

  10. Removes from jac.toml
  11. Regenerates package.json
  12. Runs npm install

Generated Files#

  • .jac/client/configs/package.json: Generated from jac.toml
  • .jac/client/configs/package-lock.json: Generated by npm
  • node_modules/: Installed packages

Important: Only jac.toml should be committed to version control.

Build Configuration#

Vite Configuration#

Vite settings are configured through the [plugins.client.vite] section:

[plugins.client.vite]
plugins = ["tailwindcss()"]
lib_imports = ["import tailwindcss from '@tailwindcss/vite'"]

[plugins.client.vite.build]
sourcemap = true
minify = "esbuild"

[plugins.client.vite.server]
port = 3000
open = true

[plugins.client.vite.resolve.alias]
"@components" = "./src/components"

Generated vite.config.js#

The system generates vite.config.js in .jac/client/configs/:

import tailwindcss from '@tailwindcss/vite'

export default {
  plugins: [tailwindcss()],
  build: {
    sourcemap: true,
    minify: 'esbuild'
  },
  server: {
    port: 3000,
    open: true
  },
  resolve: {
    alias: {
      '@components': path.resolve(__dirname, '../src/components'),
      '@jac/runtime': path.resolve(__dirname, '../compiled/client_runtime.js')
    }
  }
}

CLI Commands#

Configuration Commands#

Command Purpose
jac create --use client <name> Create new client project with jac.toml
jac add --npm <package> Add npm package
jac remove --npm <package> Remove npm package
jac add --npm Install all packages from jac.toml

Command Workflow#

# 1. Create project
jac create --use client my-app
cd my-app

# 2. jac.toml is automatically created with organized folder structure

# 3. Add custom packages
jac add --npm lodash
jac add --npm --dev sass

# 4. Customize build (edit jac.toml)

# 5. Build/serve
jac start main.jac

File Organization#

Project Structure#

project-root/
├── jac.toml                   # ← Source of truth (committed)
├── main.jac                   # Your Jac application
├── components/                # TypeScript components (optional)
├── assets/                    # Static assets
├── compiled/                  # Compiled output
│   ├── client_runtime.js
│   └── assets/
├── .jac/                      # Build artifacts (gitignored)
│   └── client/
│       ├── configs/           # Generated config files
│       │   ├── package.json   # Generated from jac.toml
│       │   ├── package-lock.json  # Generated by npm
│       │   └── vite.config.js # Generated from jac.toml
│       ├── build/             # Vite build output
│       └── compiled/          # Compiled JS
└── node_modules/              # Installed packages

Version Control#

Commit:

  • jac.toml - Your configuration
  • main.jac - Your application code
  • components/ - Your components
  • assets/ - Your assets

Don't Commit (automatically gitignored):

  • .jac/ - All build artifacts (cache, packages, client, data)
  • node_modules/ - Dependencies
  • compiled/ - Build output

Best Practices#

1. Use CLI for Package Management#

# Good: Use CLI
jac add --npm lodash

# Less ideal: Manual edit
# (requires running jac add --npm after)

2. Minimal Configuration#

Only specify what you need to override:

[plugins.client.vite]
plugins = ["tailwindcss()"]
lib_imports = ["import tailwindcss from '@tailwindcss/vite'"]

3. Keep Config Organized#

Group related settings:

[plugins.client.vite]
plugins = [...]

[plugins.client.vite.build]
sourcemap = true

[dependencies.npm]
lodash = "^4.17.21"

4. Version Pinning#

Pin versions for production:

[dependencies.npm]
lodash = "4.17.21"      # Exact for critical packages
axios = "^1.6.0"        # Caret for minor updates

Troubleshooting#

Config Not Loading#

Problem: Configuration not being applied.

Solutions:

  • Verify jac.toml is in project root
  • Check TOML syntax is valid
  • Ensure file encoding is UTF-8

Package Installation Fails#

Problem: npm install fails.

Solutions:

  • Verify Node.js and npm are installed
  • Check internet connection
  • Clear npm cache: npm cache clean --force
  • Check package names are correct

Generated Files Out of Sync#

Problem: Generated files don't match jac.toml.

Solutions:

  • Run jac add --npm to regenerate
  • Delete .jac/client/ and rebuild
  • Check jac.toml syntax