sigil.config.ts
sigil.config.ts sits in the project root and is the only place to set build and server options. Every field is optional.
import { defineConfig } from "@sigil-dev/grimoire";
export default defineConfig({
port: 3001,
dev: true,
});defineConfig is an identity function that exists for editor autocomplete — it returns its argument unchanged, so the type is the documentation.
Options
| Field | Type | Default | What it does |
|---|---|---|---|
port | number | 3000 | Port the server listens on. |
host | string | localhost | Address to bind. |
dev | boolean | — | Development mode: HMR, unminified output, verbose errors. |
routes | string | src/routes/** | Glob for where routes live. |
alias | Record<string, string> | {} | Import aliases, resolved relative to the project root. |
plugins | GrimoirePlugin[] | [] | Plugins to run. See plugins. |
bundleStrategy | "split" | "single" | "split" | Split bundles per route, or one bundle for everything. |
cspNonce | string | — | Nonce for <script> and <style> tags. |
devEditor | boolean | — | Enable the in-browser dev editor. |
vitePort | number | — | Port for the Vite dev server. |
dev
Set by the tooling rather than by hand — sigil dev turns it on, sigil start expects it off:
export default defineConfig({ dev: process.env.NODE_ENV !== "production" });In dev, the build output is unminified with source maps, the server watches files, and errors come with stack traces. sigil build compiles a production bundle that sigil start serves.
routes
Point at a different directory when routes don't live in src/routes:
export default defineConfig({ routes: "app/**" });This is a glob, and it is what the scanner walks at startup. Changing it changes the URL space along with it — the paths are derived from the file locations, so moving files moves URLs.
alias
Shorten imports and keep a directory movable:
export default defineConfig({
alias: { $lib: "src/lib", $components: "src/components" },
});import { Button } from "$components/Button";Paths resolve relative to the project root, not the importing file. Aliases are a real alternative to the baseUrl/paths dance in tsconfig.json, and the compiler and runtime agree on them without extra configuration.
bundleStrategy
"split" — the default — emits a separate bundle per route, so a visitor downloads the JavaScript for the page they asked for. "single" emits one bundle for the whole app:
export default defineConfig({ bundleStrategy: "single" });Single is smaller in total for a small app and faster to parse, at the cost of every visitor downloading code for pages they never open. It is a reasonable choice for a short app and a bad one for a large one.
cspNonce
Adds a nonce to every <script> and <style> the server emits:
export default defineConfig({ cspNonce: process.env.CSP_NONCE });The value is read once when the config module loads, not per request, so it is stable for the life of the process. Emit the matching Content-Security-Policy header yourself, from hooks, and make sure both come from the same source — a nonce in the tags that doesn't match the header blocks the scripts, which looks exactly like your JavaScript failing to load.