npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

vue-feat-cli

v26.9.1

Published

An opinionated CLI for scaffolding feature-based Vue 3 projects. Generates consistent, typed code following a layered architecture: service → composable → store → view.

Readme

vue-feat-cli

An opinionated CLI for scaffolding feature-based Vue 3 projects. Generates consistent, typed code following a layered architecture: service → composable → store → view.

Install

npm install -g vue-feat-cli

Or use directly with npx:

npx vue-feat-cli init

Quick start

# 1. Initialize — detects your stack and creates vf.config.json
vf init

# 2. Generate your first feature
vf g:feat Product

# Get help at any time
vf help
vf help generate:feat

Commands

help

Shows an overview of all commands and their descriptions. Pass a command name (or its alias) to get detailed docs with options, examples, and related commands.

vf help                    # overview interativo de todos os comandos
vf help generate:feat      # docs detalhados de generate:feat
vf help g:feat             # aliases também funcionam

init

Detects the project's installed dependencies (Pinia, Vue Router, Axios) and the TypeScript path alias, then saves vf.config.json at the project root and creates src/shared/http/client.ts.

vf init

Produces vf.config.json:

{
  "srcDir": "src",
  "featuresDir": "src/features",
  "sharedDir": "src/shared",
  "alias": "@",
  "httpClient": "fetch",
  "usesPinia": true,
  "usesVueRouter": true,
  "usesTanstackQuery": false
}

All subsequent generators read this file. If it doesn't exist, safe defaults are used (fetch, no Pinia, no Router).


g:feat <name>

Scaffolds a complete feature module under featuresDir/<name>/.

vf g:feat Product

Generated structure (with Pinia + Vue Router enabled):

src/features/product/
├── composables/
│   ├── useProductService.ts   # business logic (data refs, CRUD)
│   └── useProductPage.ts      # UI state (loading, error) — delegates to service
├── services/
│   └── product.service.ts     # HTTP layer using httpClient
├── stores/
│   └── product.store.ts       # Pinia store (Composition API) or reactive() fallback
├── types/
│   └── product.types.ts       # entity interface + CreateDto + UpdateDto
├── views/
│   └── ProductView.vue        # page component wired to useProductPage (Vue Router only)
├── routes.ts                  # lazy-loaded route record (Vue Router only)
├── components/                # feature-local components (empty)
└── index.ts                   # public barrel export

Without Vue Router, routes.ts and views/ are omitted and a blank views/ folder is created instead.


g:composable <name>

Creates a standalone composable inside a feature or in sharedDir/composables/.

vf g:composable useFilters --feature product
vf g:composable useTheme              # → src/shared/composables/useTheme.ts

g:component <name>

Creates a Vue component. Supports nested paths.

vf g:component ProductCard --feature product
vf g:component cards/ProductCard

g:service <name>

Adds a service and its types file to an existing feature.

vf g:service product --feature product

g:store <name>

Adds a store to an existing feature. Uses Pinia (defineStore) when usesPinia: true, falls back to reactive() otherwise.

vf g:store product --feature product

Architecture

Each feature follows a strict layered separation:

service.ts
    └── useXxxService.ts   ← business composable: data refs + CRUD, no UI state
            └── useXxxPage.ts   ← UI composable: loading + error, delegates to service
                    └── XxxView.vue   ← page component, calls load() on mount

Why two composables?

  • useXxxService owns domain data. Can be reused (e.g. in a modal) without triggering loading spinners.
  • useXxxPage owns UI concerns. Keeps views thin and independently testable.

The store is optional and intended for state that must be shared across features.


HTTP client

vf init generates src/shared/http/client.ts with a unified httpClient interface:

httpClient.get<T>(url)
httpClient.post<T>(url, body)
httpClient.put<T>(url, body)
httpClient.patch<T>(url, body)
httpClient.delete<T>(url)

Both the fetch and axios implementations expose the same interface, so generated services work unchanged regardless of which you choose.

The base URL is read from the VITE_API_BASE_URL environment variable.


Expected project structure

src/
├── features/        # generated modules
├── shared/
│   ├── http/
│   │   └── client.ts   # generated by vf init
│   └── composables/
└── main.ts

The path alias (@ by default) must point to src/ in your tsconfig.json:

{
  "compilerOptions": {
    "paths": { "@/*": ["./src/*"] }
  }
}

Custom Templates

You can override any scaffold template on a per-project basis by creating .hbs files in a local folder and pointing vf.config.json to it.

Setup

Option A — via vf init: Answer y when asked "Use custom templates?". This sets templatesDir: ".vf/templates" in vf.config.json and creates the empty folder.

Option B — copy all defaults for editing:

vf templates:init

This copies every built-in template to .vf/templates/, ready to edit. It also adds "templatesDir": ".vf/templates" to vf.config.json if not already set.

Option C — manual: Add "templatesDir": ".vf/templates" to your vf.config.json and create only the templates you want to override.

File structure

Your local templates must mirror the built-in structure:

.vf/templates/
├── component/
│   └── Component.vue.hbs
├── composable/
│   └── composable.ts.hbs
└── feature/
    ├── service.ts.hbs
    ├── service-crud.ts.hbs
    ├── service-composable.ts.hbs
    ├── service-composable-crud.ts.hbs
    ├── page-composable.ts.hbs
    ├── page-composable-crud.ts.hbs
    ├── store.ts.hbs
    ├── store-composable.ts.hbs
    ├── types.ts.hbs
    ├── types-crud.ts.hbs
    ├── index.ts.hbs
    ├── routes.ts.hbs
    └── View.vue.hbs

You only need to include the files you want to override — missing files fall back to the built-in defaults automatically.

Handlebars context variables

| Variable | Type | Available in | |---|---|---| | name | string | all templates — kebab-case feature name | | Name | string | all templates — PascalCase feature name | | nameCamel | string | feature templates — camelCase feature name | | alias | string | feature templates — import alias from config (e.g. @) | | usesVueRouter | boolean | feature templates |

.gitignore recommendation

Commit .vf/templates/ to your repo so the whole team uses the same overrides:

# .gitignore — do NOT ignore .vf/templates if you want team-wide overrides
# .vf/          ← remove this line if present

If you want the overrides to be personal only, add .vf/ to .gitignore.


Development

npm run dev      # run CLI with tsx (no build step)
npm run build    # compile to dist/

License

MIT