Structura aplicatie multi-templates

La un moment dat incepusem sa postez prin Ce proiecte au membrii DevForum, dar am esuat lamentabil dupa ce mi-am dat seama ca n-am tinut cont de nici o regula de dezvoltare, si am ajuns sa ma impotmolesc in propriul cod.

Am un magazin online facut unui prieten de ceva timp si ma tot roaga sa-i fac updateuri mici, dar lipsa de motivatie e enorma, chiar si cu plata pe munca prestata. M-am gandit ca, crearea unui SaaS ar fi o solutie mai buna, i-am prezentat-o, ii surade ideea si e de acord cu plata unui abonament modic lunar pentru folosirea unei platforme de genul. Ba mai mult, mi-a spus ca mai are o prietena ce ar vrea sa-i creez un site asemanator, dar motivatia tinde spre zero. Stiu ca exista deja un Saas in Romania (gomag) destul de avansat, nu ma gandesc la concurenta, ci strict la faptul ca am 4 5 cunostinte care ar putea folosi un astfel de serviciu daca l-as duce la bun sfarsit (s-ar putea sa esuez la fel si cu aceasta idee, dar chiar si asa, pe parcursul evolutiei proiectului invat destul de multe lucruri, astfel ca nu e chiar atat de inutil).

Am pornit cu gandul sa creez un SaaS bazat pe structura deja creata pentru magazinul prietenului, si sa incep cu un minim de templateuri (doua la numar), pentru ca nu as vrea ca toti clientii sa aibe design. Problema ce a aparut e la structurarea aplicatiei. Fiind scrisa in Angular, lazy loadingul este posibil pe module, dar din cauza multi-templateurilor, s-ar putea sa repet din nou figura cu spaghetele. Am pus pe foaie, si in prima faza mi-au iesit 2 structuri:

A)
app/template1/home
-------------------/products
-------------------/profile
-------------------/cart
app/template2/home
-------------------/products
-------------------/profile
-------------------/cart

B)
app/home/template1
-------------/template2
app/products/template1
-----------------/template2

De ex, modulul products are 2 pagini, una pentru listarea produselor, si alta pentru detaliile unui produs. Pentru fiecare pagina, este nevoie de 2 versiuni (cate una pentru fiecare template).

C) ?
M-am mai gandit ca pot grupa templateurile intr-un modul separat, cu structura pentru fiecare pagina:
app/templates/template1/ pagini (care de fapt sunt componente: home, products-list, products-detail, cart, checkout, profile, etc)
app/templates/template2/ (componente duplicate de la template1, dar cu sectiuni si stiluri proprii).

Problema este ca la primul request (la accesarea siteului), va fi adus templateul respectiv (obiect detaill) aplicatiei web plus toate detaliile acestuia (in mare parte, stiluri personalizate care vor suprascrie stilurile default). Dupa asta, aplicatia va face loading componentei template care se matchuieste cu rezultatul http-requestului.

Ce ma intereseaza este ca la oricare dintre cele 3 variante, as vrea sa renunt la datele templateului nefolosit, iar bundle-ul aplicatiei sa fie minim. De ex, daca am 100 templateuri, adminul siteului va alege doar unul, dar cand siteul va fi accesat, vreau sa-l incarce doar pe cel folosit, nu si celelalte 99 care nu vor fi niciodata utilizate.

Orice varianta as folosi, mi se pare ca pentru fiecare template, duplic codul, iar size-ul aplicatiei pateste acelasi lucru, creste inutil. Pentru ca siteul clientului X va avea de suferit pentru ca mai am inca 99 templateuri create pentru alti clienti.

Ma gandesc ca e problema de structurare aplicatie + lazy loading module sau chiar componente si nu vad o solutie pentru a nu creste inutil size-ul aplicatiei. Nu stiu daca este posibila ducerea templateurilor in backend/db si incarcarea intr-o componenta dinamica a sectiunilor (componente card, grid, header, menu …). asta suna complicat si probabil eronat

Merci :grin:

1 Like

Eu unul consider că-i puțin greșit să folosești Angular pentru un magazin. Sau orice alt framework JS.

  1. Chiar este nevoie de reactivitate într-un magazin online? Da, este nice to have, dar este cu adevărat nevoie?
  2. Nu te poți baza pe conexiunea clientului. Sau pe configurările clientului. Mi s-a întâmplat de nu știu câte ori să nu încarce un js din cauza vreunei reguli din adblock => site-ul era inutilizabil.
  3. Orice framework ai folosi și oricât de light ar fi, este digerat cu greu de dispozitive mobile. Sigur, nu de iPhone 15 sau de Galaxy S24, dar presupun că nu toți au flagship-uri, nu?

Eu aș merge pe o structură de genul:

themes/tema-de-bază
themes/tema-de-bază/modul-1
themes/tema-de-bază/modul-2

themes/tema-1
themes/tema-1/modul-2

themes/tema-2
themes/tema-2/modul-1

I.e. să ai o temă de bază iar celelalte teme doar să suprascrie ce este nevoie (deși nu sunt sigur cum funcționează treaba asta în Angular).

Avantajul imediat al acestei abordări este că permiți utilizatorilor să pună doar tema proprie în Git.

Din ce inteleg eu, esti deja angajat si asta e doar ceva pe langa. Personal nu as recomanda sa te apuci sa faci un framework de e-commerce daca nu te poti dedica full time la treaba asta. Mai degraba iei ceva deja existent si faci teme si modificari acolo unde cerintele utilizatorului nu se aliniaza cu ce ofera framework-ul.

da, sunt deja angajat, dar as putea aloca constant intre 20 si 30 ore pe weekend pentru proiectul asta :smiley:

@iamntz, sincer, cred ca mi-ar fi mult mai greu sa incep dezvoltarea in js pur sau in frameworkuri C#/Java pe MVC. Alte solutii, nu cunosc.

Ca si idee, fiecare client al SaaS-ului ar urma sa aibe 2 aplicatii web. Una de administrare, iar cealalta, magazinul online. din aplicatia de administrare va putea seta templateul dorit + alte functionalitati ale shop-ului. Pentru AdminApp, m-am gandit ca toti clientii pot folosi aceeasi instanta, si le pot furniza adrese de tipul www.mySaaS,com/DorelShop/Admin. Pentru shop, ar fi domeniul dorel-shop,com, cars-shop,com, etc. Dar toate siteurile de tip shop ar fi instante noi ale aceluiasi proiect. Practic, fiecare client va avea cate o instanta pentru backend + frontend.

partea cu stilurile am rezolvat-o, fac preloading stilurilor inainte de a randa pagina, aici avantajul este ca stilurile templateurilor sunt fisiere css separate si pot spune renderului pe care sa-l incarce. De partea templateurilor, problema e ca trebuie sa le definesc intr-un modul, dar sa le folosesc in altele (orders, products, profile, etc). Cred ca varianta C ar fi cea mai plauzibila, iar pentru fiecare template sa creez cate un modul, ce va fi incarcat lazy. Cand initializez aplicatia (accesare), incarc modulul templateului si de acolo m-am pierdut, pentru ca trebuie sa se comporte ca root, si de acolo mai departe rutarea pentru modulele aplicatiei :))

cea mai tembela varianta pentru fiecare pagina este asta:
in componenta home, am un templateId primit si randez in functie de un if:

app.component.html

<app-home-template1 *ngIf="templateId === 1"></app-home-template1>
<app-home-template2 *ngIf="templateId === 2"></app-home-template2>
...

problema cum ziceam mai sus, este ca in cazul asta, mainjs-ul meu contine toate templateurile si creste in size => performanta scazuta. Aici nu imi dau seama cum sa elimin toate componentele neutilizate.

Nu o lua pe drumul asta doar pentru ca stii. Proiectele de genul “mai fac o platforma pentru ca pot, in timpul liber” duc la acelasi rezultat: lipsa timpului pentru mentenanta va duce la abandonarea proiectului. Crede-ma, toti cei de aici cu ceva experienta au cate o poveste de asta.

4 Likes

Practic doar repeți fix jobul inițial :))

La un moment dat vei avea motivație zero să lucrezi și la platforma asta pentru că va fi outdated, și vei dori să faci iar alta cu ceva ce e cool la momentul respectiv.

Pune-i un Magento sau un Wordpress și lasă-l să se descurce.

1 Like

meammm, nu sunt chiar raspunsurile pe care le asteptam :))

am lucrat pe SaaS-uri financiare si mi-a placut ideea de a avea un produs propriu si a-l imbunatatii permanent, pe langa asta avand si satisfactia cresterii numarului de clienti, unul cate unul (asta in cazul bun :)) voiam sa incerc ceva asemanator (pe microservicii), de aici am ramas cu dorinta de a avea un produs propriu in productie, oricat de banal ar fi, dar care sa vad ca e folosit :grin: un lucru greu de facut, mai ales de unul singur. chiar daca nu-mi surade, cam aveti dreptate :unamused:

Nu înțelege greșit, nu-ți zice nimeni să nu faci, ci doar să nu faci cu js :smiley:

2 Likes

Eu nu inteleg de ce iti trebuie template-uri diferite pentru fiecare shop/client. Adica ce difera intre ele?
Themes diferite e una, dar templates diferite e alta.

Trebuie sa te hotarasti daca vrei sa faci SaaS sau un CMS customizabil de catre fiecare client.
Cred ca e mult mai usor sa construiesti un SaaS decat un CMS cu zeci de customizari posibile.

Cu templates diferite mi se pare ca de fapt faci o aplicatie noua pentru fiecare client nou. Apoi ce presupune un template/modul/client nou? Doar html si css sau si javascript?

Daca instalezi sistemul la fiecare client, de ce ai deploya toate templates la toti clienti?
Iti trebuie un build system care sa extraga doar template-ul dorit si sa construiasca un bundle specific fiecarui client/template.

Eu folosesc Angular Workspace si Nrwl Nx pentru un monorepo cu mai multe aplicatii + shared libs, vezi poate te ajuta.

2 Likes

acum daca ma gandesc mai bine, cred ca faceam cumva confuzie intre cele doua. Si CMS-ul imi pare un nucleu de SaaS, dar mult mai configurabil (pe mai departe), iar serviciul isi pierde din identitate. Ma gandeam la templateuri diferite pentru ca poate un client vrea sa aibe grid produse de 4x5, iar altul 2x4, unul vrea un sidebar, altul nu. unul vrea 5 sectiuni in homepage, altul vrea doar 3 produse si un numar de contact. Dar da, m-as incurca destul de mult inca de la inceput si e o sansa si mai mare sa renunt pe parcurs :woozy_face: Pot aplica stiluri customizabile destul de usor pe componente si ajutat de directive, paginile or sa arate diferit, chiar daca va fi acelasi template.

Problema cu deployul era asa. Am 3 module principale ale aplicatiei:

home-module (www.website.com),
products-module (www.website.com/products, www.website.com/products/1),
cart-module (www.website.com/cart)

toate cele 3 sunt bundleuri js, atasate la main prin lazy loading in functie de ruta accesata. Eu, daca aveam 10 templateuri, pe toate le-as fi scris in templates-module, iar pe acesta ar fi trebuit sa-l import in fiecare modul de mai sus. Ma gandisem cumva sa sparg modulul de templateuri pe fiecare tip si asa sa am template-home.module, template-products.module, template-cart.module. Asa sizeul pentru fiecare ar fi mai mic, iar in home.module as fi incarcat strict doar template-home.module. Acum singura problema ar fi ca trebuie sa elimin celelalte 9 componente neutilizate din acest modul. Si asa am ajuns la gandul ca mai bine sparg tot in module si ajung la template1-home.module, template2-home.module, template1-products.module, template2-products.module, … Asa, cand s-ar incarca modulul de home, pentru ca stiu ce template trebuie adus (salvat undeva in cookies), as incarca modulul respectiv (template1 sau template2, … ). Citisem undeva ca nu mai trebuiesc declarate ca export class , pentru a putea fi injectate dinamic in alte module, dar n-am avut mai mult timp. Pe scurt, ma impotmolisem la structurarea modulelor in aplicatie.

Instalarea pentru fiecare client as fi vrut sa fie cat mai usor facuta, dintr-un script, daca ar fi deploy pe linux cum am invatat acum, dintr-o linie de comanda sa pornesc o noua instanta pentru fiecare client:

 - am pachetul pe server (cu toate cele 10 templateuri)
 -  run nohup http-server localhost:9000? & # client 1 isi seteaza din admin panel - template 5
 -  run nohup http-server localhost:9001? & # client 2 isi seteaza din admin panel - template 1
 -  run nohup http-server localhost:9002? & # client 3 isi seteaza din admin panel - template 7
 # oricand, fiecare dintre ei isi pot alege un alt template, in cazul asta n-as putea face build customizabil cu un singur template

dar pentru toti clientii pornesc cate o instanta ale aceluiasi pachet, identificarea clientilor s-ar face prin port sau domeniu.

Mie imi era frica de ideea ca daca as avea 30 clienti si 30 build-uri (unul pentru fiecare), la un nou redeploy, va trebui sa fac copy paste pentru fiecare si sa rulez script. Am uitat ca exista jenkins si se poate rezolva cu click click :man_facepalming: :crazy_face:

Cred ca fix de Angular Workspace aveam nevoie in cazul de mai sus. :grin:

multumesc

Nu degeaba te-am intrebat daca un template (sau un modul de template nou) contine si javascript diferit fata de celelalte templates, sau contine doar html si css diferit si te astepti ca toate templates sa ruleze acelasi cod javascript?

Tie ti se pare OK sa ai cate un template.module diferit pentru fiecare client, si deci si pentru fiecare pagina pentru ca un client nu are doar o pagina? Suna ca si cum pentru fiecare client ai dezvolta o aplicatie noua/diferita aproape in intregime (acele templateX.module).

De ce nu ai dezvolta un singur modul per feature (home.module, products.module, cart.module) pentru toti clientii si implementezi customizarile (grid produse 4x5, 2x4, sidebar sau no sidebar, etc.) direct in modulele respective, astfel incat clientii sa-si poata customiza modulele? Eventual mai vii cu Themes peste, deci doar css, fara templates (html) sau cod diferit pentru fiecare client.

2 Likes

da, asta e cea mai buna si simpla solutie de implementat. M-am incurcat in “lucruri complicate si complexe”. Asa incepusem, dar ideea de “templateuri diferite” mi-a dat totul peste cap :))