Skip to content

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 make

Do wyboru pozostają dwa generatory:

GeneratorZastosowanie
moduleTworzenie nowego modułu wraz z rejestracją w aplikacji
modelDodanie 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.js

Rejestracja 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:

PlikWstawiana treść
src/router/routes.jsimport <nazwa>Routes oraz ...<nazwa>Routes,
src/i18n/en/index.jsimport tłumaczeń i klucz modułu
src/i18n/pl/index.jsjak wyżej
src/menu-items.jspozycja w menu, w grupie modules
quasar.config.jssrc/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

  1. Dodaj klucz tłumaczenia dla menu — wpis <nazwa> w src/i18n/en/menu-items.js oraz src/i18n/pl/menu-items.js. Generator go nie tworzy, więc bez tego w menu pojawi się surowy klucz.
  2. Podmień ikonę — generator wstawia zawsze description.
  3. Przenieś pozycję do właściwej grupy menu — generator zapisuje ją w grupie modules; moduł należący do ustawień trzeba przenieść do settings.
  4. Uruchom generator model — dopiero on tworzy katalogi components/, composables/, pages/, forms/ oraz api/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 ​

PlikWstawiana treść
src/modules/blog/routes/index.jsimport tras modelu oraz wpis w tablicy
src/modules/blog/trans/en/index.jsimport i klucz
src/modules/blog/trans/pl/index.jsimport 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 dirs

Markery 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.js

Plik 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: main

Skrypt wykonuje kolejno:

  1. Zamienia nazwę pakietu z kebab-case na camelCase katalogu — content-builder staje się contentBuilder.
  2. Pobiera archiwum poleceniem git archive --remote=ssh://git@bitbucket.org/moonbite/<pakiet>-module-frontend.git.
  3. 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).

Made by Moonbite