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

# 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.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.

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-client/utils" = "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-client/utils': 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