@chrisluyi/daas-cli
v1.4.0
Published
Zero-config build/dev/test CLI for React micro-frontend (MFE) apps using [rsbuild](https://rsbuild.dev) + [Module Federation 2](https://module-federation.io).
Readme
daas-cli
Zero-config build/dev/test CLI for React micro-frontend (MFE) apps using rsbuild + Module Federation 2.
MFE apps have no build config files — no rsbuild.config.ts, no vitest.config.ts. The CLI owns all of it.
Packages
| Package | Version | Description |
|---|---|---|
| @chrisluyi/daas-cli | 1.1.0 | CLI binary — install this as your only devDependency |
| @chrisluyi/rsbuild-config | 1.1.0 | rsbuild config factory + vitest config — arrives transitively |
| @chrisluyi/template | 1.0.0 | MFE scaffold templates (services / containers / components structure) |
Quickstart (3 commands)
mkdir my-mfe && cd my-mfe
echo '{"name":"my-mfe"}' > package.json
npx @chrisluyi/daas-cli init
bun install
daas devYour MFE is now running at http://localhost:3000 with Module Federation 2, React, hot-reload, and Vitest — zero config required.
Installation
# In your MFE project
bun add -D @chrisluyi/daas-cli
# or npm
npm install -D @chrisluyi/daas-clidaas-cli is the only devDependency you need. It ships rsbuild, vitest, @testing-library/react, happy-dom, and all tooling as its own dependencies. Do not install these separately.
Commands
daas init [--template default]
daas dev [target] [--port <n>] [--json]
daas build [target] [--json]
daas test [--json]
daas info [--json]daas init
Interactive scaffold powered by @clack/prompts. Prompts for remote config URL, port, and app name, then writes starter files.
┌ daas-cli — scaffold new MFE
│
◇ Remote config URL?
│ https://your-org.example.com/daas-config.json
│
◇ Dev server port?
│ 3001
│
◇ App name? (leave blank to use package.json name)
│ mfe-auth
│
◇ Does this app expose additional components beyond ./App?
│ No
│
◆ Scaffolding mfe-auth...
│ ✓ Created src/App.tsx
│ ✓ Created src/App.test.tsx
│ ✓ Created tsconfig.json
│ ✓ Updated package.json
│
└ Done! Run: bun install && daas devWhat gets created (minimal scaffold):
src/
├── App.tsx # minimal React component
└── App.test.tsx # smoke test
tsconfig.json # jsx: react-jsx, strict mode
package.json # scripts + daas config injected--template default scaffolds the full opinionated structure:
src/
├── App.tsx # entry — renders AppContainer
├── containers/
│ └── AppContainer.tsx # data-fetching component
├── components/
│ └── App.tsx # presentational component
├── services/
│ └── index.ts # service layer stub
└── config/
├── regions/ # per-region config (for v1.5 targets)
├── platforms/ # per-platform config
└── products/ # per-product configdaas dev
Starts the rsbuild dev server with HMR and Module Federation 2 in remote mode.
daas dev # uses port from package.json#daas
daas dev --port 3002 # override port at runtime
daas dev sg-foo-mb-dev # v1.5: activate region/product/platform targetdaas build
Production build to ./dist. Always fetches fresh remote config — fatal if network unavailable.
daas build
daas build sg-foo-mb-prod # v1.5: build for a specific target
daas build --json # machine-readable output (for CI / AI agents)daas test
Runs Vitest with happy-dom, @testing-library/react, and @testing-library/jest-dom pre-configured. The following browser APIs are mocked automatically so MFE tests work without any extra setup:
window.matchMediaResizeObserverIntersectionObserverwindow.scrollTo/scrollByURL.createObjectURL/revokeObjectURL
daas test
daas test --jsonWriting tests — import everything from @chrisluyi/daas-cli/test (no direct vitest or @testing-library imports needed):
import { render, screen, describe, test, expect, userEvent } from "@chrisluyi/daas-cli/test"
import MyComponent from "./MyComponent"
describe("MyComponent", () => {
test("renders a button", async () => {
render(<MyComponent />)
await userEvent.click(screen.getByRole("button"))
expect(screen.getByText("Clicked!")).toBeInTheDocument()
})
})Adding extra setup — append your own setup files after the built-in mocks via package.json#daas.setupFiles:
{
"daas": {
"configUrl": "...",
"port": 3001,
"setupFiles": ["./src/test-setup.ts"]
}
}Your setup file can override any of the default mocks or add new ones.
daas info
Prints the fully resolved project state — useful for debugging and AI agent diagnosis.
daas info --jsonExample output:
{
"ok": true,
"command": "info",
"cliVersion": "1.1.0",
"appName": "mfe-auth",
"port": 3001,
"configUrl": "https://your-org.example.com/daas-config.json",
"manifest": {
"name": "mfe-auth",
"exposes": { "./App": "./src/App" }
},
"remoteJson": {
"version": "1.0.0",
"minCliVersion": "1.0.0",
"shared": { "react": "18.3.1", "react-dom": "18.3.1" },
"rsbuildConfigVersion": 1
},
"isMonorepo": false
}Per-App Config (package.json#daas)
All MFE-specific configuration lives in package.json:
{
"name": "mfe-auth",
"scripts": {
"dev": "daas dev",
"build": "daas build",
"test": "daas test"
},
"devDependencies": {
"@chrisluyi/daas-cli": "^1.1.0"
},
"daas": {
"configUrl": "https://your-org.example.com/daas-config.json",
"port": 3001,
"coverage": {
"lines": 80,
"branches": 80
}
}
}| Field | Required | Description |
|---|---|---|
| configUrl | Yes | URL of the remote JSON config owned by your platform team |
| port | Yes | Dev server port — must be unique per MFE in a monorepo |
| coverage | No | Vitest coverage thresholds |
| setupFiles | No | Extra Vitest setup files appended after the built-in browser mocks |
Optional Manifest (mf.manifest.json)
Only needed when exposing more than just ./App:
{
"name": "mfe-auth",
"exposes": {
"./App": "./src/App",
"./LoginButton": "./src/components/LoginButton"
}
}If absent, name derives from package.json#name (scope stripped), and exposes defaults to { "./App": "./src/App" }.
Remote JSON (served by your platform team)
The URL in configUrl must serve a JSON file like this:
{
"version": "1.0.0",
"minCliVersion": "1.0.0",
"releaseNotesUrl": "https://your-org.example.com/daas-cli/releases",
"shared": {
"react": "18.3.1",
"react-dom": "18.3.1"
},
"rsbuildConfigVersion": 1
}This controls which version of shared dependencies all your MFEs use via Module Federation 2's singleton negotiation. The CLI fetches this at dev startup (5-min cache) and always fresh at build time.
Monorepo Support
daas init detects monorepos by walking parent directories for bun.lockb or package.json#workspaces. In a monorepo:
daas-cliis not added to the app'sdevDependencies(it's resolved from the workspace root)- Each MFE has its own
portinpackage.json#daas
my-monorepo/
├── package.json # workspaces: ["packages/*"]
├── bun.lockb
└── packages/
├── mfe-auth/ # daas dev → port 3001
│ └── package.json # { "daas": { "port": 3001, ... } }
└── mfe-dashboard/ # daas dev → port 3002
└── package.json # { "daas": { "port": 3002, ... } }v1.5 — Multi-Region Target System
Target strings let you select region/product/platform/environment at dev and build time:
daas dev sg-foo-mb-dev
│ │ │ └─ environment (dev / staging / prod)
│ │ └──── platform (mb = mobile, wb = web, etc.)
│ └──────── product (may contain hyphens)
└──────────── region (sg, us, eu, …)When a target is provided:
- The CLI resolves a
TargetContextfrom the string tsconfig.daas.jsonis generated (gitignored) with path aliases:@region-config→./src/config/regions/<region>@platform-config→./src/config/platforms/<platform>@product-config→./src/config/products/<product>
- Environment variables are injected at build time:
DAAS_REGION,DAAS_PRODUCT,DAAS_PLATFORM,DAAS_ENV
Use daas init --template default to scaffold the config layer folder structure.
Exit Codes
| Code | Meaning | What to do |
|---|---|---|
| 0 | Success | — |
| 1 | General error (build/test failure) | Check output above the JSON |
| 2 | Config error (missing configUrl, bad manifest) | Run daas init or fix package.json#daas |
| 3 | CLI too old (minCliVersion not met) | Upgrade @chrisluyi/daas-cli |
| 4 | Remote JSON fetch failed | Check network / VPN (only fatal in build) |
| 5 | Config version mismatch | Upgrade @chrisluyi/daas-cli |
--json Output Contract
All commands except init support --json — always use this in CI and AI agent workflows.
Success:
{
"ok": true,
"command": "build",
"appName": "mfe-auth",
"output": "./dist",
"cliVersion": "1.1.0"
}Error:
{
"ok": false,
"command": "build",
"exitCode": 4,
"error": "Could not fetch remote config: HTTP 503",
"suggestion": "Check network connectivity or VPN.",
"cliVersion": "1.1.0"
}AI Agent Support (Claude Code)
Register the bundled skill so Claude Code understands daas-cli without hallucinating commands:
# Per-project
mkdir -p .claude/skills
cp node_modules/@chrisluyi/daas-cli/skill.md .claude/skills/daas-cli.md
# Or globally
cp node_modules/@chrisluyi/daas-cli/skill.md ~/.claude/skills/daas-cli.mdAI agent workflow:
# 1. Always start here to understand current state
daas info --json
# 2. Run commands and parse stdout JSON
daas build --json
# { "ok": true, ... } or { "ok": false, "exitCode": N, "error": "...", "suggestion": "..." }Development (this repo)
bun install
bun test # run all tests
bun run build # build both packages to dist/
bun run lint # biome checkSee docs/DEVELOPMENT.md for the full release workflow.
