CLI

@preact-mvc/cli is the project toolkit — Angular CLI shaped: scaffold apps, generate views/controllers/services/ modules/islands, run the project's vite and vitest, add integrations, and bump framework deps.

Install

npm install -g @preact-mvc/cli
# or run without installing:
npx @preact-mvc/cli <command>

The binary is pmvc (with PreactMVC as a longer alias). It is dependency-free Node — it must run before a project has node_modules at all.

New application

pmvc new my-app                  # core app: module + router + two views + a test
pmvc new my-app --islands      # + worker-island demo (contract, worker, route)
pmvc new my-app --tailwind     # + Tailwind v4 wired into vite and styles
pmvc new my-app --skip-install # write files only

The scaffold is the same shape this site documents: AppModule with RouterModule.forRoot, an AppShell view, a standalone HelloView, a stateful CounterView, jsdom test stubs, and the decorators-friendly tsconfig. Existing files are never overwritten unless --force; -d/--dry-run prints the plan without writing.

Generators

pmvc g view user-card        # src/app/user-card/user-card.view.tsx (+ .test.tsx)
pmvc g controller checkout   # checkout.controller.ts — @Controller view logic
pmvc g service session       # session.service.ts — @Injectable model
pmvc g module admin          # admin.module.ts — feature module
pmvc g island ticker         # islands/ticker.contract.ts + workers/ticker.worker.tsx

pmvc g view report --path src/app/admin   # override the target directory
pmvc g view report --skip-tests           # no spec file

Generators print the next step — the route entry or declaration to add — rather than editing files in place. The island generator emits the contract-first shape (worker factory inside the contract, islandComponent on the shell); run pmvc add islands first if the atoll packages are not installed.

Serve, build, test

Thin pass-throughs to the project's own toolchain — every flag after the command goes to vite/vitest:

pmvc serve --port 3000      # vite dev server
pmvc build                  # tsc --noEmit && vite build (--no-typecheck to skip)
pmvc test                   # vitest run
pmvc test --watch           # vitest watch mode

Integrations

pmvc add tailwind   # deps + vite plugin + styles.css
pmvc add islands    # @preact-mvc/atoll + atoll-island + @atolljs/core

Updates

pmvc update                 # bump every @preact-mvc/* dep to latest, npm install
pmvc update --to 0.2.0      # pin to a specific release
pmvc update -d              # show the planned changes only
pmvc update --include-atoll # also bump @atolljs/* deps

pmvc version prints the CLI version plus the detected framework dep ranges of the project you're inside.

Generated tests mount views through InjectorContext.Provider — a bare render() has no injector context, so inject() throws by design. The generated vite config keeps the whole preact graph in one vitest realm for the same reason.