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

@leviutima/create-fsd-app

v0.1.0

Published

Scaffold front-end projects with Feature-Sliced Design

Readme

create-fsd-app

CLI que gera projetos front-end já estruturados em Feature-Sliced Design (FSD), com lint de arquitetura configurado desde o primeiro commit — nada de deixar a estrutura de pastas se corromper com o tempo.

Suporta três stacks: Vite + React, Next.js e Expo (React Native).

Por quê

FSD organiza o front-end em camadas (app → pages → widgets → features → entities → shared), onde cada camada só pode importar das camadas abaixo dela, e cada slice só expõe o que quer via uma "public API" (index.ts). Isso é fácil de explicar e fácil de violar sem querer — um import direto num arquivo interno de outro slice, ou um import "pra cima" na hierarquia, passa despercebido em review e corrói a arquitetura aos poucos.

Este gerador cria o projeto já com:

  • a estrutura de pastas FSD pronta;
  • um slice de exemplo (entities/user) mostrando o padrão de public API;
  • eslint-plugin-boundaries configurado pra bloquear, no lint normal do dia a dia, tanto imports entre camadas na direção errada quanto imports que furam a public API de um slice;
  • steiger (linter oficial do FSD) configurado pra pegar violações estruturais que o ESLint não cobre (slice sem referência, index de camada indevido, etc).

Instalação e uso

Distribuído no npm como @leviutima/create-fsd-app (com escopo — o nome sem escopo create-fsd-app já pertence a outro pacote). Não precisa instalar nada antes, é só rodar via npx:

npx @leviutima/create-fsd-app meu-projeto

Sem argumento, ele pergunta o nome do projeto e a stack via prompt interativo. Também dá pra passar tudo direto:

npx @leviutima/create-fsd-app meu-projeto --template next

Se preferir instalar global em vez de usar npx toda vez:

npm install -g @leviutima/create-fsd-app
create-fsd-app meu-projeto

Opções

| Flag | Valores | Descrição | |---|---|---| | [project-name] | texto livre | Nome do projeto e da pasta criada (no diretório atual). Se omitido, é perguntado. | | -t, --template <name> | vite | next | expo | Qual stack usar. Se omitido, é perguntado. |

Stacks suportadas

| Stack | O que é | Scripts gerados | |---|---|---| | Vite | SPA React puro | dev, build, lint, lint:arch, check | | Next.js | App Router (v14), com src/app fazendo dupla função: roteamento do Next + camada app do FSD | dev, build, start, lint, lint:arch, check | | Expo | React Native, entrada clássica (App.tsx na raiz + expo/AppEntry.js) | start, android, ios, web, lint, lint:arch, check |

Detalhes por stack:

  • Vite: src/main.tsx monta <App /> no #root do index.html.
  • Next: src/app/layout.tsx e src/app/page.tsx são os arquivos especiais do App Router; src/app/App.tsx é a camada de composição FSD de fato e está marcada com "use client" porque o slice de exemplo usa useState (o Next trata tudo como Server Component por padrão).
  • Expo: a UI do slice de exemplo usa <View>/<Text> em vez de <div>. O tsconfig.json restringe o include a App.tsx + src/** porque expo/tsconfig.base usa moduleResolution: "node", que não resolve os tipos do steiger (não afeta o app rodando, só o tsc --noEmit).

Limitação conhecida: o template Expo foi validado com npm install, lint, lint:arch e tsc --noEmit, mas não foi testado num simulador/dispositivo real (esse ambiente não tem Expo Go). Rode npx expo start numa máquina com Expo Go pra confirmar visualmente antes de depender dele em produção.

Estrutura gerada

meu-projeto/
├── src/
│   ├── app/         # composição raiz — providers, entry point
│   ├── pages/        # (vazia) telas/rotas
│   ├── widgets/      # (vazia) blocos de UI compostos de features/entities
│   ├── features/     # (vazia) casos de uso interativos
│   ├── entities/
│   │   └── user/      # slice de exemplo
│   │       ├── index.ts        # public API — só isso pode ser importado de fora
│   │       ├── model/
│   │       │   ├── store.ts
│   │       │   └── types.ts
│   │       └── ui/
│   │           └── UserCard.tsx
│   └── shared/       # (vazia) código sem regra de negócio (ui kit, libs, utils)
├── eslint.config.js  # regras de fronteira entre camadas
├── steiger.config.ts # linter de arquitetura FSD
└── tsconfig.json

Regra de import entre camadas (de cima pra baixo, cada uma só enxerga as de baixo):

app → pages → widgets → features → entities → shared

shared não importa de nenhuma outra camada. Um slice (ex.: entities/user) só pode ser importado através do seu index.ts — importar direto entities/user/model/store de fora do slice é bloqueado pelo lint.

Rode npm run check (ou lint + lint:arch separados) dentro do projeto gerado pra validar isso.

Como funciona por dentro

create-fsd-app/
├── src/
│   └── index.ts       # CLI: parseia args, pergunta nome/stack, copia o template e substitui {{PROJECT_NAME}}
└── templates/
    ├── vite/           # cada pasta é um projeto completo e auto-contido
    ├── next/
    └── expo/

O src/index.ts só faz três coisas: pergunta nome e stack (via commander + prompts), copia templates/<stack> para o diretório de destino, e substitui o placeholder {{PROJECT_NAME}} nos arquivos que precisam dele (package.json, app.json, index.html, src/app/App.tsx — os que existirem em cada template).

Os três templates são independentes entre si (arquivos duplicados, não compartilhados) — é proposital: cada um precisa evoluir conforme a stack correspondente muda, e compartilhar via symlink ou build step adicionaria complexidade desproporcional pra um gerador de escopo pessoal.

Desenvolvendo o CLI

npm run dev     # tsup em watch mode
npm run build   # build de produção (dist/index.js)

Pra testar uma mudança sem publicar:

npm run build
create-fsd-app teste --template vite   # usa o link global feito com `npm link`

Se o comando create-fsd-app parar de funcionar depois de mexer no bin do package.json, rode npm unlink -g @leviutima/create-fsd-app && npm link de novo pra regenerar os shims globais.

Publicando uma nova versão

A publicação no npm é feita pelo GitHub Actions via Trusted Publishing (OIDC) — não existe token de npm guardado em lugar nenhum, nem manual nem em secret do repositório. Quem autoriza o publish é a combinação repositório + workflow, configurada uma vez em npmjs.com → pacote → Settings → Trusted Publisher.

Pra cortar uma release:

npm version patch   # ou minor / major — atualiza package.json e cria a tag
git push --follow-tags

O push da tag vX.Y.Z dispara o workflow .github/workflows/publish.yml, que builda e publica automaticamente. Também dá pra disparar manualmente pela aba Actions do GitHub (workflow_dispatch).

Licença

MIT