Skip to main content

stacks-build

Use when working with the Stacks build system - building component libraries, CLI binaries, server Docker images, documentation, or the framework core. Covers @stacksjs/build, buddy build commands, build actions, and the server build pipeline.

Source facts

Repository
stacksjs/stacks
Last source activity
October 10, 2026 at 17:09
Detected SKILL.md language
English
Stars
633
Forks
20

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
stacks-build
description
Use when working with the Stacks build system - building component libraries, CLI binaries, server Docker images, documentation, or the framework core. Covers @stacksjs/build, buddy build commands, build actions, and the server build pipeline.
license
MIT
compatibility
Bun >= 1.3.0, TypeScript
allowed-tools
Read Edit Write Bash Grep Glob
# Stacks Build System ## Key Paths - Core package: `storage/framework/core/build/` - Build actions: `storage/framework/core/actions/src/build/` - Main build action: `storage/framework/core/actions/src/build.ts` - Buddy commands: `storage/framework/core/buddy/src/commands/build.ts` - Server build: `storage/framework/server/build.ts` - Server Dockerfile: `storage/framework/server/Dockerfile` - Types: `storage/framework/core/types/src/cli.ts` ## Source Files ``` build/src/ ├── index.ts # intro() and outro() - build logging and timing ├── web-types.ts # Web types generation for IDE support └── build.ts # Package build config (Bun.build) actions/src/build/ ├── cli.ts # Build Buddy CLI binary ├── server.ts # Build server Docker image ├── core.ts # Build all framework core packages ├── stacks.ts # Orchestrate CLI + core builds ├── component-libs.ts # Build the `components` library packages ├── libs.ts # Build every configured library package ├── docs.ts # Build documentation ├── desktop.ts # Build desktop app └── views.ts # Build frontend views ``` ## Build Types ```typescript type BuildOption = | 'components' | 'webComponents' | 'elements' | 'functions' | 'libs' | 'docs' | 'views' | 'stacks' | 'all' | 'buddy' | 'server' type BuildOptions = { [key in BuildOption]: boolean } & CliOptions interface CliOptions { verbose?: boolean silent?: boolean quiet?: boolean cwd?: string background?: boolean timeoutMs?: number project?: string } ``` ## CLI Commands ```bash buddy build # Interactive build buddy build components # All component libraries buddy build:components # Alias buddy build:web-components # Web Components library only buddy build:functions # The `functions` library packages buddy build:libs # Every configured library package buddy build:cli # Buddy CLI binary buddy build:server # Server Docker image buddy build:core # All framework core packages buddy build:stacks # CLI + core (full framework) buddy build:docs # Documentation site buddy build:desktop # Desktop application buddy build:views # Frontend views # Flags buddy build -c # --components buddy build -w # --web-components buddy build -f # --functions buddy build -l # --libs buddy build -d # --docs buddy build -b # --buddy buddy build -s # --stacks buddy build --server --verbose --project [name] ``` ## Standard Build Pattern For a library barrel or a package with public subpaths, preserve the module graph with the shared transpiler. Identifier-minifying bundles have produced invalid re-export bindings on supported Bun versions. Separate bundles also duplicate shared objects across entrypoints, such as validation's schema proxy. ```typescript import { rm } from 'node:fs/promises' import { frameworkExternal, intro, outro, transpilePackage } from '../build/src' const { startTime } = await intro({ dir: import.meta.dir }) await rm('./dist', { recursive: true, force: true }) await transpilePackage({ dir: import.meta.dir, external: frameworkExternal() }) await outro({ dir: import.meta.dir, startTime, result: { errors: [], warnings: [] } }) ``` The helper emits every source module and its declaration with whitespace-only minification. Keep package-specific assets, declaration rewriting, and runtime probes around this call. Use Bun.build for intentional executable bundles and verify the emitted artifact. ORM inference builds validation before ORM because the published ORM imports validation's narrow runtime entry. ## Releasing libraries out of `resources/` `resources/functions` and `resources/components` are not limited to one npm package each. `config/library.ts` carries a `packages` array, and each entry claims a slice of one of those directories by glob and becomes its own package with its own name, manifest, dist and version: ```ts // config/library.ts packages: [ // A file may be claimed by more than one package. { name: '@acme/fx', kind: 'functions', include: ['*.ts'], exclude: ['internal/**'] }, { name: '@acme/fx-dates', kind: 'functions', include: ['dates/**'] }, { name: '@acme/ui', kind: 'components', include: ['ui/**'], prefix: 'acme' }, { name: '@acme/elements', kind: 'web-components', include: ['ui/**'], prefix: 'acme' }, ] ``` The older single-package `functions` / `webComponents` keys still work: they normalize into the same list, so a config written before `packages` existed keeps building exactly one package. When `packages` is set, they are ignored. | Kind | Built by | Published entry | |---|---|---| | `functions` | sources staged into the package's `src/`, then `transpilePackage` | `dist/index.js`, one module per source | | `components` | stx `buildComponentLibrary` | `dist/index.js`, tree-shakeable per-component modules | | `web-components` | the same compile | `dist/bundle.js`, one self-registering script | ```bash buddy libs # what each package resolved to, on disk buddy libs --json # the same, machine-readable buddy build:libs # build them all (also `buddy build --libs`) buddy build:functions # just the `functions` packages buddy build:components # just the `components` packages buddy build:web-components # just the `web-components` packages buddy libs:publish --dry-run buddy libs:publish # after a build; refuses a package with no dist ``` Packages build in `storage/framework/libs/packages/<dir>/`, where `<dir>` is the unscoped npm name unless the entry sets `dir`. The whole directory is generated and gitignored. ### Things that will stop a build, on purpose - **A package that matches no files.** Nearly always a typo'd glob, and the alternative is publishing an empty tarball. The release path skips unmatched packages instead, so an app that never filled in `resources/` is not blocked. - **Two packages that resolve to the same directory** (`@acme/ui` and `@other/ui` both unscope to `ui`). Give one an explicit `dir`. - **stx ambient globals in a `functions` package.** `state`, `useDark` and the rest are injected into an stx page entry and exported by nothing, so a bundled copy compiles and then throws `ReferenceError` on the consumer's first call. Either import the names explicitly, or set `runtime: 'stx'` on the package to declare that it is only ever consumed from inside an stx app. ### Release flow `buddy release` runs `generate/lib-entries`, which stages sources and writes each manifest without compiling - so a broken library config fails before a tag exists rather than after. Versions follow the project version unless a package pins its own, which is why the build (not the generate) is what CI runs after the bump, and `buddy libs:publish` after that. ## Build Utilities (index.ts) ```typescript async function intro(options: { dir: string, pkgName?: string, styled?: boolean }): Promise<{ startTime: number }> async function outro(options: { dir: string, startTime: number, result: any, pkgName?: string }): Promise<void> ``` `outro()` handles two result formats: - **Bun.build**: checks `result.success` and `result.logs` - **esbuild**: checks `result.errors` array ## Server Build Pipeline (7 stages) ``` 1. Stop running stacks-server Docker container 2. Clean previous build artifacts (app, config, dist, docs, storage) 3. Build framework server (compile ./src/index.ts) 4. Build user app files (compile ./app/**/*.{ts,js}) 5. Fix import paths (replace storage/framework/server → dist) 6. Clean unwanted exports from dist files 7. Build Docker image (if cloud deployment enabled) ``` ## Build Action Enums ```typescript enum Action { BuildViews = 'build/views' BuildStacks = 'build/stacks' BuildComponentLibs = 'build/component-libs' BuildVueComponentLib = 'build-vue-component-lib' BuildWebComponentLib = 'build-web-component-lib' BuildFunctionLib = 'build-function-lib' BuildCli = 'build/cli' BuildCore = 'build/core' BuildDesktop = 'build/desktop' BuildDocs = 'build/docs' BuildServer = 'build/server' } ``` ## Build Tool Stack | Tool | Usage | |------|-------| | **Bun** | Primary bundler (`target: 'bun'`, `format: 'esm'`) | | **stx** | Component library builds | | **bun-plugin-dtsx** | TypeScript declaration generation | | **Docker** | Server containerization | | **@babel/traverse** | AST traversal for export cleanup | ## Gotchas - **Two result formats** - `outro()` must handle both Bun.build and esbuild formats - **Server build mutates import paths** - stage 5 rewrites references in compiled output - **Core build is sequential** - packages built one at a time, failures collected and reported - **Docker build requires cloud config** - only builds if cloud deployment is enabled - **Component libraries compile through stx**, not Vite. `buildComponentLibrary` emits its own index and each generated component registers its custom element on import, which is why a `web-components` package needs no entry file of its own - it publishes `bundle.js` instead of `index.js`. - **A library barrel is generated with `.ts` specifiers on purpose.** `transpilePackage` rewrites relative `.ts` to `.js` on the way into `dist`. An extensionless specifier survives as-is and only resolves under Bun, so the package installs cleanly and fails on first import from Node or Vite. - **`build:stacks` builds CLI first** - Buddy binary compiled before core packages - **Server build cleans aggressively** - deletes app, config, dist, docs, storage before rebuild - **The build package has @babel deps** - uses Babel for AST traversal during export cleanup ## Package build contracts `@stacksjs/build` exports `transpilePackage` and `frameworkExternal(extras?)` alongside intro/outro. Inspect a neighboring core build.ts before configuring declaration roots or external dependencies; the source example is a pattern, not a universal package manifest. Type-only dependencies that escape the package degrade consumers even when local paths resolve. `validateDeclarations(dir)` and `validateRuntimeExports(dir)` are native checks used by the build contract. A type declaration export without a matching runtime file is a package failure, not a successful build. The current public implementation is `storage/framework/core/build/src/index.ts`. Use Bun/TS for supporting build scripts and pickier for lint.
View on GitHub