Skip to content

Struktura katalogów ​

Układ projektu wynika z konwencji Quasara, rozszerzonej o strukturę modułową w katalogu src/modules/. Cała logika biznesowa znajduje się w modułach, a najwyższy poziom src/ zawiera wyłącznie elementy globalne.

Drzewo projektu ​

├── _templates/plop        szablony generatora (model/, module/)
├── build/env-parser.js    ładowanie plików .env
├── public/
├── src/
│   ├── App.vue            root: <router-view> + reset cache przy zmianie języka
│   ├── menu-items.js      cała nawigacja panelu (modules[] + settings[])
│   ├── assets/img/
│   ├── boot/
│   │   ├── app/           ui.js — domyślne Notify/Loading/LoadingBar
│   │   └── packages/      axios, i18n, yup, feather-icons, vue-query
│   ├── composables/       useNestedRoutes.js (jedyny globalny composable)
│   ├── css/               app.scss, partiale _mixins/_form/_table/...,
│   │                      quasar.variables.scss, moon.variables.scss, fonts/
│   ├── i18n/              instance.js, pluralization-rules.js, en/, pl/
│   ├── icons/app/         własne SVG (kolekcja "app" dla unplugin-icons)
│   ├── layouts/           MasterLayout, AuthLayout, BlankLayout
│   ├── modules/           ← logika biznesowa, opisana niżej
│   ├── router/            index.js (guard), routes.js (składanie tras)
│   └── stores/            index.js — createPinia()
├── auto-imports.d.ts      generowane, commitowane
├── components.d.ts        generowane, commitowane
├── install-module.sh
├── plopfile.cjs
└── quasar.config.js

Moduły ​

Projekt zawiera szesnaście modułów:

auth  blog  contentBuilder  cookie  core  faq  media  menu
page  redirect  review  seo  setting  slider  staticText  user

Pełnią one trzy różne role:

RolaModułyCharakterystyka
JądrocoreKlasa Http, komponenty Base* i V*, composables useCoreTable i useFormSubmit, breadcrumbs, guardy, funkcje pomocnicze. Nie jest modułem domenowym
Infrastrukturaauth, media, contentBuilder, seoUżywane przez pozostałe moduły
DomenaresztaRealizują ten sam wzorzec CRUD

Katalog w camelCase, ścieżki i klucze w kebab-case

Nazwa katalogu modułu zapisywana jest w konwencji camelCase (contentBuilder, staticText), natomiast ścieżki API, nazwy tras i klucze i18n używają kebab-case (/content-builder/..., static-text.static-texts.index).

Anatomia modułu ​

Poniższy układ, pokazany na przykładzie modułu blog, powtarza się we wszystkich modułach domenowych:

src/modules/blog/
├── api/
│   ├── keys.js                     klucze cache dla Vue Query (per model)
│   ├── endpoints/article.js        cienkie wrappery axiosa
│   ├── queries/article.queries.js  useArticleDetailQuery()
│   └── mutations/article.mutations.js  useArticleSaveMutation()
├── components/
│   ├── BlogArticleForm.vue         <Moduł><Model>Form
│   ├── BlogArticlesTable.vue       <Moduł><Modele>Table
│   ├── BlogCategoryForm.vue
│   ├── BlogCategoriesTable.vue
│   ├── BlogCategoryReorderTree.vue
│   └── BlogCategoryReorderTreeItem.vue
├── forms/
│   ├── article.form.js             initialValues() + validationSchema()
│   └── category.form.js
├── pages/
│   ├── articles/                   ArticleIndexPage / CreatePage / EditPage
│   └── categories/                 + CategoryReorderPage
├── routes/
│   ├── index.js                    agreguje trasy modułu
│   ├── articles.js
│   └── categories.js
├── stores/
│   └── category.js                 Pinia — tylko tam, gdzie potrzebny
└── trans/
    ├── en/  index.js, articles.js, categories.js, messages.js
    └── pl/  index.js, articles.js, categories.js, messages.js

Przeznaczenie katalogów ​

KatalogZawartość
api/endpointsFunkcje wywołujące API — bez logiki i bez obsługi błędów
api/keys.jscreateEntityKeys("/blog/articles") — klucze cache Vue Query
api/queriesComposables oparte na useQuery — pobieranie danych
api/mutationsComposables oparte na useMutation — zapis i unieważnianie cache
formsWartości początkowe i schemat walidacji yup, bez części wizualnej
componentsKomponenty modułu, rejestrowane globalnie
composablesComposables modułu; auto-importowane tylko wtedy, gdy katalog figuruje w quasar.config.js
pagesStrony przypisane do tras, z podziałem na modele
routesTrasy z podziałem na modele oraz plik index.js
storesStore'y Pinia — tylko tam, gdzie potrzebny jest stan poza cache serwera
servicesCzysta logika domenowa, bez wywołań HTTP
helpers, utils, constants, configsElementy pomocnicze; utils bywa auto-importowany
transTłumaczenia modułu w wersjach en i pl

Szkieletu nie tworzy się ręcznie

Cały powyższy układ generuje npm run make, opisany w Modułach i generatorach.

Aliasy importów ​

Aliasy zdefiniowane są w quasar.config.js w sekcji build.alias:

js
// quasar.config.js
alias: {
  modules: fileURLToPath(new URL("./src/modules", import.meta.url)),
  composables: fileURLToPath(new URL("./src/composables", import.meta.url)),
}

Uzupełniają je aliasy domyślne Quasara. Pełna lista odwzorowana jest w jsconfig.json — dzięki temu działają podpowiedzi w edytorze:

AliasŚcieżka
modules/*src/modules/*
composables/*src/composables/*
src/*src/*
app/** (katalog główny projektu)
layouts/*src/layouts/*
boot/*src/boot/*
stores/*src/stores/*
assets/*src/assets/*
components/*src/components/*
pages/*src/pages/*

W praktyce zastosowanie znajdują przede wszystkim dwa pierwsze:

js
import { api } from "modules/core/services/http";
import { articleKeys } from "modules/blog/api/keys";

oraz alias layouts/ w definicjach tras:

js
component: () => import("layouts/MasterLayout.vue")

Aliasy components/ i pages/ prowadzą do nieistniejących katalogów

Pochodzą z domyślnej konfiguracji Quasara, ale w tym projekcie src/components i src/pages nie istnieją — odpowiadające im pliki leżą wewnątrz modułów.

Made by Moonbite