Motyw
Moduły i generatory
Moduł jest samodzielnym katalogiem w src/modules/. W projekcie nie występuje automatyczne wykrywanie modułów — rejestracja przebiega jawnie i polega na dopisaniu modułu do kilku plików zbiorczych. Czynność tę wykonuje generator.
Generator Plop
bash
npm run makeDo wyboru pozostają dwa generatory:
| Generator | Zastosowanie |
|---|---|
module | Tworzenie nowego modułu wraz z rejestracją w aplikacji |
model | Dodanie modelu CRUD do istniejącego modułu |
Konfiguracja generatorów znajduje się w plopfile.cjs, a szablony w katalogu _templates/plop/{module,model}/.
Generator module
Generator zadaje jedno pytanie:
Module name (snake_case, e.g. blog):Tworzone pliki
src/modules/<nazwa>/api/keys.js
src/modules/<nazwa>/routes/index.js
src/modules/<nazwa>/trans/en/index.js
src/modules/<nazwa>/trans/pl/index.js
src/modules/<nazwa>/trans/en/<nazwy>.js
src/modules/<nazwa>/trans/pl/<nazwy>.js
src/modules/<nazwa>/trans/en/messages.js
src/modules/<nazwa>/trans/pl/messages.jsRejestracja modułu w aplikacji
Generator dopisuje moduł do pięciu plików zbiorczych — na tym polega jego zasadnicza wartość, bo w projekcie nie ma automatycznego wykrywania modułów:
| Plik | Wstawiana treść |
|---|---|
src/router/routes.js | import <nazwa>Routes oraz ...<nazwa>Routes, |
src/i18n/en/index.js | import tłumaczeń i klucz modułu |
src/i18n/pl/index.js | jak wyżej |
src/menu-items.js | pozycja w menu, w grupie modules |
quasar.config.js | src/modules/<nazwa>/composables do auto-importu oraz src/modules/<nazwa>/components do auto-rejestracji komponentów |
Wstawiana pozycja menu ma następującą postać:
js
// src/menu-items.js
{
icon: "description",
name: t("menu-items.<nazwa>", 2),
to: { name: "<nazwa>.<nazwy>.index" },
access: "<nazwa>.<nazwy>.index",
},Czynności do wykonania ręcznie po uruchomieniu generatora module
- Dodaj klucz tłumaczenia dla menu — wpis
<nazwa>wsrc/i18n/en/menu-items.jsorazsrc/i18n/pl/menu-items.js. Generator go nie tworzy, więc bez tego w menu pojawi się surowy klucz. - Podmień ikonę — generator wstawia zawsze
description. - Przenieś pozycję do właściwej grupy menu — generator zapisuje ją w grupie
modules; moduł należący do ustawień trzeba przenieść dosettings. - Uruchom generator
model— dopiero on tworzy katalogicomponents/,composables/,pages/,forms/orazapi/endpoints.
Lista modułów odczytywana jest jednorazowo
Plik plopfile.cjs odczytuje zawartość src/modules w momencie startu. Nowo utworzony moduł pojawia się na liście generatora model dopiero po ponownym uruchomieniu npm run make.
Generator model
Generator zadaje dwa pytania:
Select module: (lista katalogów z src/modules)
Model name (singular, snake_case, e.g. blog_post):Nazwa modelu odmieniana jest wewnętrznym helperem plural, zgodnie z zasadami języka angielskiego: category daje categories, box daje boxes, a article — articles.
Tworzone pliki
Dla modułu blog i modelu article powstają następujące pliki:
src/modules/blog/api/endpoints/article.js
src/modules/blog/api/queries/article.queries.js
src/modules/blog/api/mutations/article.mutations.js
src/modules/blog/forms/article.form.js
src/modules/blog/components/BlogArticleForm.vue
src/modules/blog/components/BlogArticlesTable.vue
src/modules/blog/pages/articles/ArticleIndexPage.vue
src/modules/blog/pages/articles/ArticleCreatePage.vue
src/modules/blog/pages/articles/ArticleEditPage.vue
src/modules/blog/routes/articles.js
src/modules/blog/trans/en/articles.js (pomijany, jeśli istnieje)
src/modules/blog/trans/pl/articles.js (pomijany, jeśli istnieje)Do pliku src/modules/blog/api/keys.js dopisywana jest linia z kluczami cache.
Modyfikowane pliki modułu
| Plik | Wstawiana treść |
|---|---|
src/modules/blog/routes/index.js | import tras modelu oraz wpis w tablicy |
src/modules/blog/trans/en/index.js | import i klucz |
src/modules/blog/trans/pl/index.js | import i klucz |
Elementy pozostawione do uzupełnienia
Wygenerowany kod zawiera komentarze // TODO: add fields, // TODO: add validation oraz <!-- TODO: add form fields -->. Pełną ścieżkę prowadzącą od uruchomienia generatora do działającego CRUD-a opisuje sekcja Krok po kroku.
Markery generatora
Generator nie analizuje składni kodu, lecz odszukuje dokładne komentarze i wstawia treść bezpośrednio przed nimi:
js
// --place where generator will inject new routes
// --place where generator will inject new translations
// --place where generator will inject new menu items
// --place where generator will inject new auto-import dirs
// --place where generator will inject new components dirsMarkery występują w plikach src/router/routes.js, src/modules/*/routes/index.js, src/i18n/{en,pl}/index.js, src/menu-items.js oraz quasar.config.js.
Komentarzy tych nie wolno usuwać
Usunięcie markera nie powoduje żadnego ostrzeżenia — generator po prostu przestaje wstawiać treść w danym miejscu. Objawia się to dopiero tym, że nowy moduł nie działa mimo poprawnie wygenerowanych plików.
Dodatkowo w pliku src/router/routes.js obowiązuje następująca reguła:
js
// --place where generator will inject new routes
// coreRoutes should be the last one
...coreRoutes,Tablica coreRoutes zawiera trasę /:catchAll(.*)* obsługującą błąd 404 i musi pozostać ostatnia, w przeciwnym razie przechwyci trasy modułów dopisanych poniżej.
Anatomia modułu na przykładzie blog
src/modules/blog/
├── api/
│ ├── keys.js
│ ├── endpoints/{article,category}.js
│ ├── queries/{article,category}.queries.js
│ └── mutations/{article,category}.mutations.js
├── components/
│ ├── BlogArticleForm.vue BlogArticlesTable.vue
│ ├── BlogCategoryForm.vue BlogCategoriesTable.vue
│ └── BlogCategoryReorderTree.vue BlogCategoryReorderTreeItem.vue
├── forms/{article,category}.form.js
├── pages/
│ ├── articles/ ArticleIndexPage / CreatePage / EditPage
│ └── categories/ CategoryIndexPage / CreatePage / EditPage / ReorderPage
├── routes/ index.js, articles.js, categories.js
├── stores/ category.js
└── trans/
├── en/ index.js, articles.js, categories.js, messages.js
└── pl/ index.js, articles.js, categories.js, messages.jsPlik routes/index.js agreguje trasy poszczególnych modeli i przechowuje marker generatora:
js
// src/modules/blog/routes/index.js
import articleRoutes from "modules/blog/routes/articles";
import categoryRoutes from "modules/blog/routes/categories.js";
const routes = [
articleRoutes,
categoryRoutes,
// --place where generator will inject new routes
];
export default routes;Plik trans/pl/index.js udostępnia nazwę modułu w formie pojedynczej i mnogiej:
js
// src/modules/blog/trans/pl/index.js
export default {
name: "Artykuł | Artykuły",
articles,
categories,
messages,
};Model bez pełnego zestawu plików
Nie każdy model wymaga wszystkich elementów schematu. Pliki BlogCategoryReorderTree.vue i CategoryReorderPage.vue stanowią przykład funkcji dołożonej poza zakresem generatora — wystarczyło dopisać dziecko trasy w routes/categories.js.
Instalacja modułu z repozytorium
Moduły utrzymywane osobno instalowane są skryptem:
bash
sh install-module.sh <nazwa-pakietu> [wersja] # domyślna wersja: mainSkrypt wykonuje kolejno:
- Zamienia nazwę pakietu z kebab-case na camelCase katalogu —
content-builderstaje sięcontentBuilder. - Pobiera archiwum poleceniem
git archive --remote=ssh://git@bitbucket.org/moonbite/<pakiet>-module-frontend.git. - Usuwa katalog docelowy przez
rm -rf src/modules/<katalog>, rozpakowuje archiwum i kasuje plik zip.
Skrypt usuwa cały katalog modułu
Wszystkie lokalne zmiany w tym module przepadają bezpowrotnie i powinny zostać zacommitowane przed instalacją.
Skrypt nie rejestruje modułu w aplikacji
Zadaniem install-module.sh jest wyłącznie wypakowanie plików. Wpisy w src/router/routes.js, src/i18n/{en,pl}/index.js, src/menu-items.js oraz quasar.config.js trzeba dodać ręcznie, analogicznie do tego, co robi generator module.
Skrypt wymaga ponadto dostępu SSH do Bitbucketa oraz narzędzia GNU sed (w systemie macOS — gsed).