ဆောင်းပါးများ
Multi-layout နှင့် multi-theme architecture design pattern
frontend တစ်ခုက theme 100+ နဲ့ layout အမျိုးမျိုးကို ပံ့ပိုးရင်း custom logic တွေ shared component ထဲ စိမ့်ဝင်မသွားအောင် ဘယ်လိုဖွဲ့စည်းမလဲ။ ဒီဆောင်းပါးမှာ core / view / theme leaf အလွှာခွဲပုံ၊ type သတ်မှတ်ထားတဲ့ config၊ theme family ပြည့်စုံမှုစမ်းသပ်ချက်နဲ့ theme CSS ကို လိုအပ်ချိန်မှသာ load လုပ်ပုံ၊ အလွှာတစ်ခုချင်းစီရဲ့ အပေးအယူတွေကို ရှင်းပြထားပါတယ်။
· အပ်ဒိတ်လုပ်ခဲ့သည် · 3 မိနစ် ဖတ်ရန်
တစ်ခါက ကြီးမားတဲ့ Nx / Angular frontend platform တစ်ခုရဲ့ architecture ကို ပြန်လည်ဖွဲ့စည်းဖို့ တာဝန်ယူခဲ့ဖူးပါတယ်။ အဲဒီ platform ဟာ theme 100 ကျော်နဲ့ layout အမျိုးမျိုးကို ပံ့ပိုးရပြီး၊ မကြာခဏဆိုသလို အခြား team member တွေက multi-layout, multi-theme subtask တွေကို ကိုယ့်ရဲ့ development habit နဲ့ကိုက်ညီတဲ့ပုံစံနဲ့ အပြီးသတ်ကြပါတယ်။ အဲဒီလို ရေရှည်စုလာတာနဲ့ technical debt ဖြစ်လာပြီး၊ လိုအပ်ချက်တစ်ခုတည်းအတွက် implementation logic မျိုးစုံ တစ်ပြိုင်နက် ရှိနေစေပါတယ်။
ဒီဆောင်းပါးမှာ အဲဒီတုန်းက အဓိက design ကို ရှင်းလင်းတင်ပြထားပါတယ်။ အလွှာတွေကို ဘယ်လိုခွဲသလဲ၊ theme 100 ကျော်လုံး ပြည့်စုံနေအောင် ဘယ်လိုလုပ်သလဲ၊ browser က အသုံးဝင်တဲ့ CSS ကိုပဲ download လုပ်အောင် ဘယ်လိုလုပ်သလဲ။ မူရင်း production code ကို အများပြည်သူထံ မထုတ်ပြနိုင်တဲ့အတွက် မူရင်း code နဲ့ စိတ်ကူးဖန်တီးထားတဲ့ theme သုံးခုကို သုံးပြီး ပြန်လည်အကောင်အထည်ဖော်ကာ frontend-engineering-case-studies မှာ တင်ထားပါတယ်။ တိုက်ရိုက်စမ်းသပ်နိုင်တဲ့ အွန်လိုင်း Demo လည်း ရှိပါတယ်။ ဆောင်းပါးထဲက code တွေအားလုံး ဒီ public version က လာတာပါ။
အရင်ဆုံး အနှစ်ချုပ်ပြောရရင်- “ဘယ်လိုပုံပေါ်မလဲ” နဲ့ “ဘာလုပ်မလဲ” ကို ခွဲပြီး၊ compiler နဲ့ test တွေက theme 100 ကျော်ရဲ့ တစ်သမတ်တည်းဖြစ်မှုကို ထိန်းသိမ်းပေးစေပါ။
ပြဿနာက အရောင်ပြောင်းတာတစ်ခုတည်း မဟုတ်ပါ#
Theme များစွာကို ပံ့ပိုးရာတွင် အများဆုံးတွေ့ရသည့် အစပြုနည်းမှာ မျှဝေသုံးစွဲသည့် component ထဲတွင် အခြေအနေစစ်ဆေးချက်များ ထည့်ခြင်းဖြစ်သည်။ ဥပမာ၊ A theme တွင် ခလုတ်တစ်ခု ထပ်လိုပြီး B theme တွင် အစီအစဉ်ကာလအတွင်း အခြားစာမျက်နှာတစ်ခုသို့ လမ်းညွှန်ပေးရန် လိုအပ်သည်:
if (theme === 'a') {
showExtraButton = true;
} else if (theme === 'b' && isCampaign) {
redirectTo = '/campaign';
}
theme သုံးခုပဲရှိတဲ့အခါ ဒီလိုရေးတာ မြန်ပါတယ်။ theme 100 ဖြစ်လာတဲ့အခါ shared component တစ်ခုချင်းစီမှာ “theme တစ်ခုတည်းအတွက်ပဲ မှန်တဲ့” branch တွေ အများကြီး ရှိလာပါတယ်။ အကျိုးဆက်ကတော့-
- Theme A အတွက် လိုအပ်ချက်ကို ပြင်လိုက်တာက Theme B ကို တိတ်တဆိတ် ပျက်စီးစေနိုင်ပြီး၊ B ကို စစ်ဆေးဖို့ ဘယ်သူ့မှာမှ တာဝန်မရှိပါ။
- ကွာခြားချက်တစ်မျိုးတည်းကို component မတူတဲ့နေရာတွေမှာ တစ်ခါစီရေးကြပြီး၊ ရေးပုံတွေလည်း မတူကြပါ။
- theme အသစ်ထည့်တဲ့အခါ “ဖြည့်ရမယ့်နေရာအားလုံးကို ဖြည့်ပြီးပြီလား” ဆိုတာ ဘယ်သူမှ မသေချာနိုင်ပါ။
ဒါကြောင့် ဖြေရှင်းရမယ့်အရာက အရောင်ပြောင်းတာတစ်ခုတည်း မဟုတ်ပါဘူး။ theme တစ်ခုချင်းစီရဲ့ အသွင်အပြင်နဲ့ product ပိုင်းမှာ ကွဲပြားခွင့်ပေးရင်း၊ theme family တစ်ခုလုံးကို ပြည့်စုံပြီး ခန့်မှန်းလို့ရအောင် ထိန်းထားဖို့ပါ။
အရင်ဆုံး ခွဲခြားပါ- layout နဲ့ theme ဟာ မတူညီတဲ့အရာနှစ်ခုပါ#
အိမ်နဲ့ ဥပမာပေးရင် အလွယ်ဆုံးနားလည်နိုင်ပါတယ်။
- ဖွဲ့စည်းပုံနဲ့ ပိုက်လိုင်းများ- တိုင်၊ ရေမီးလိုင်း။ အိမ်တိုင်းမှာ အတူတူဖြစ်ပြီး နေထိုင်သူရဲ့အကြိုက်ကြောင့် ပြောင်းလဲသင့်တာ မဟုတ်ပါ။
- layout- အခန်းဖွဲ့ပုံ။ အိပ်ခန်းနှစ်ခန်းလား သုံးခန်းလား၊ ဧည့်ခန်းက ဘယ်မှာလဲ။ “အရာတွေကို ဘယ်လိုစီမလဲ” ဆိုတာကို သတ်မှတ်ပါတယ်။
- theme- အတွင်းအလှဆင်ပုံ။ နံရံအရောင်၊ ပစ္စည်းအသား၊ ထောင့်ဝိုင်းမှုအရွယ်အစား။ “အရာတွေ ဘယ်လိုပုံပေါ်မလဲ” ဆိုတာကို သတ်မှတ်ပါတယ်။
frontend ထဲမှာ ဒီသုံးခုဟာ မတူညီတဲ့ layer တွေနဲ့ အသီးသီးကိုက်ညီပါတယ်။ အတူရောလိုက်ရင် “အရောင်တစ်ခု ပြောင်းဖို့ data flow ကို ပြင်ရ” တဲ့အခြေအနေ ဖြစ်လာတတ်ပါတယ်။
လေးလွှာဖွဲ့စည်းပုံ#
Runtime theme id
│
▼
selector ──► theme leaf (complete typed config)
│
▼
shared view ◄── data service
│ └──► actions facade
▼
pure core
အောက်ခြေကနေ အပေါ်ကို ကြည့်ရအောင်-
core: ပုံပေါ်အောင်ပဲ လုပ်ပါ#
core component တွေက “ပြင်ဆင်ပြီးသား၊ ချက်ချင်း render လုပ်နိုင်တဲ့” data ကိုပဲ လက်ခံပြီး၊ user ရဲ့ intent ကိုပဲ အပြင်ကို ထုတ်ပေးပါတယ်။ လက်ရှိ theme ဘာလဲဆိုတာ မသိသလို routing နဲ့ API response format ကိုလည်း မကိုင်တွယ်ပါဘူး။ brand asset တွေကိုလည်း reference မလုပ်ပါဘူး။
export class ThemeCardCoreComponent {
readonly appearance = input.required<ThemeAppearance>();
readonly content = input.required<ThemeContent>();
readonly items = input.required<readonly ShowcaseItem[]>();
readonly selectedId = input<string | null>(null);
readonly itemSelected = output<ShowcaseItem>();
readonly selectionCleared = output<void>();
}
theme အားလုံးက core ကို အတူသုံးတဲ့အတွက် သက်ရောက်မှုအကျယ်ဆုံးဖြစ်ပြီး စည်းမျဉ်းတွေလည်း အတင်းကျပ်ဆုံးပါ။ လိုအပ်တဲ့ input တွေကိုပဲ လက်ခံပြီး၊ intent တွေကိုပဲ output အဖြစ် ထုတ်ပေးပါ။
view: ညှိနှိုင်းပေးပါ#
view က အလယ်ခံပါ။ data service ကနေ data ယူပြီး core လိုအပ်တဲ့ပုံစံအဖြစ် ပြောင်းပေးပါတယ်။ core က intent ထုတ်ပေးတဲ့အခါ actions facade ဆီ လွှဲပေးပါတယ်။
@Component({
selector: 'case-study-theme-card-view',
providers: [FeatureActionsFacade, FeatureDataService],
template: `
<case-study-theme-card-core
[appearance]="appearance()"
[content]="themeContent()"
[items]="data.items()"
[selectedId]="actions.selectedId()"
(itemSelected)="select($event)"
(selectionCleared)="actions.reset()"
/>
`,
})
export class ThemeCardViewComponent { /* ... */ }
data ဘယ်ကလာသလဲ (data service)၊ ခလုတ်နှိပ်ရင် ဘာလုပ်ရမလဲ (actions facade) ဆိုတာတွေမှာ ကိုယ်ပိုင်ရှင်းလင်းတဲ့ နယ်နိမိတ်တွေရှိလို့ screen component တွေထဲမှာ ဟိုတစ်စ ဒီတစ်စ ပြန့်ကျဲမနေပါဘူး။
layout ကို ဒီ layer မှာ ထားသင့်ပါတယ်။ အခန်းဖွဲ့ပုံကွဲပြားတာတွေကို shared view မတူတာတွေအဖြစ် သတ်မှတ်နိုင်ပါတယ်။ အဲဒီ view တွေက data service နဲ့ facade တစ်စုံတည်းကို ချိတ်ဆက်ထားပြီး core ကို စီစဉ်ပုံပဲ ကွဲပြားပါတယ်။ ရှင်းလင်းလွယ်အောင် public Demo မှာ shared view တစ်ခုပဲ ရှိပါတယ်။ production မှာ ပြန်လည်ဖွဲ့စည်းခဲ့တုန်းကတော့ 26 ခု ထည့်သွင်းခဲ့ပါတယ်။
theme leaf: theme တစ်ခုစီအတွက် leaf တစ်ခု#
theme တစ်ခုစီဟာ ပါးလွှာတဲ့ component တစ်ခုဖြစ်ပြီး၊ ပြည့်စုံတဲ့ အသွင်အပြင် config တစ်ခုကို ရွေးကာ shared view ဆီ ပေးပို့တာတစ်ခုတည်းကိုပဲ လုပ်ပါတယ်။
@Component({
selector: 'case-study-theme-aurora',
imports: [ThemeCardViewComponent],
template:
'<case-study-theme-card-view [appearance]="appearance" data-theme-leaf="aurora" />',
})
export class ThemeAuroraComponent {
protected readonly appearance = THEME_APPEARANCES.aurora;
}
အဲဒီထဲမှာ business condition လုံးဝမရှိပါဘူး။ production မှာ ကိုယ်စားပြုနိုင်တဲ့ ပြည့်စုံသော theme leaf တစ်ခုကို refactor လုပ်ပြီးနောက် 23 လိုင်းပဲ ရှိပါတယ်။ အရင်ရေးပုံမှာတော့ အဲဒီလမ်းကြောင်းတစ်ခုတည်းကပဲ လိုင်းရာနဲ့ချီ ရှိခဲ့ပါတယ်။
selector: family ထဲက အဖွဲ့ဝင်တွေကို အတိအလင်း စာရင်းပြုစုပါ#
selector က runtime ရဲ့ theme id ကို အခြေခံပြီး သက်ဆိုင်ရာ leaf ကို render လုပ်ပါတယ်-
@switch (theme()) {
@case ('aurora') { <case-study-theme-aurora /> }
@case ('summit') { <case-study-theme-summit /> }
@default { <case-study-theme-default /> }
}
မြင်ရတာက သာမန်ပဲဖြစ်ပေမယ့် “အတိအလင်းဖော်ပြထားခြင်း” က အဓိကပါ။ ဘယ် theme တွေရှိတယ်၊ တစ်ခုစီက ဘယ် leaf နဲ့ ကိုက်ညီတယ်ဆိုတာ တစ်ချက်ကြည့်ရုံနဲ့ သိနိုင်သလို တစ်ခုချင်းစီကို test လုပ်စစ်ဆေးနိုင်ပါတယ်။
ဘယ်ဟာတွေလိုသလဲဆိုတာ compiler ကို စစ်ဆေးခိုင်းပါ#
theme များလာတဲ့အခါ အကြောက်ရဆုံးက တစ်ခုခုကျန်ခဲ့တာပါ။ theme အသစ်ထည့်ပြီး config ဖြည့်ဖို့ မေ့သွားတာ၊ config format ပြောင်းလိုက်ပေမယ့် theme အဟောင်းတချို့က လိုက်မပြင်မိတာမျိုး ဖြစ်နိုင်ပါတယ်။
လုပ်ရမယ့်အရာက theme စာရင်းကို single source အဖြစ် အရင်ရေးပြီး၊ TypeScript ရဲ့ satisfies ကို သုံးကာ theme တစ်ခုစီအတွက် ပြည့်စုံတဲ့ config တစ်ခု ရှိစေဖို့ သတ်မှတ်တာပါ။
export const DEMO_THEMES = ['default', 'aurora', 'summit'] as const;
export type DemoTheme = (typeof DEMO_THEMES)[number];
export interface ThemeAppearance {
readonly density: 'comfortable' | 'compact';
readonly id: DemoTheme;
readonly stylesheetHref: `themes/${string}.css`;
}
export const THEME_APPEARANCES = {
default: { id: 'default', density: 'comfortable', stylesheetHref: 'themes/default.css' },
aurora: { id: 'aurora', density: 'comfortable', stylesheetHref: 'themes/aurora.css' },
summit: { id: 'summit', density: 'compact', stylesheetHref: 'themes/summit.css' },
} satisfies Record<DemoTheme, ThemeAppearance>;
DEMO_THEMES မှာ theme တစ်ခု ထပ်ထည့်ပြီး THEME_APPEARANCES ကို မဖြည့်ထားရင် compile လုပ်တာ မအောင်မြင်ပါဘူး။ field နာမည်စာလုံးပေါင်းမှားတာနဲ့ CSS path format မမှန်တာတွေလည်း အလားတူပါပဲ။
satisfies ကို type ကို တိုက်ရိုက်သတ်မှတ်တာထက် သုံးရဲ့ давуу талက shape-ийг စစ်ဆေးရင်း value တစ်ခုချင်းစီရဲ့ бодит төрлийг хадгалдагт оршино။ Ингэснээр дараа нь THEME_APPEARANCES.aurora-ийг ашиглахдаа ерөнхий ThemeAppearance төрөл рүү өргөсөхгүй.
test-үүдနဲ့ theme family တစ်ခုလုံးကို ထိန်းသိမ်းပါ#
compiler က config ကို စစ်ဆေးနိုင်ပေမယ့် “ဒီ theme က တကယ် render လုပ်လို့ရသလား” ဆိုတာကို မစစ်ဆေးနိုင်ပါဘူး။ ဒီအပိုင်းကို family completeness test တွေက တာဝန်ယူပြီး၊ ကြေညာထားတဲ့ theme တစ်ခုချင်းစီကို စာရင်းကောက်စစ်ဆေးပါတယ်-
it.each(DEMO_THEMES)('renders the %s family leaf', (theme) => {
const fixture = TestBed.createComponent(ThemeSelectorComponent);
fixture.componentRef.setInput('theme', theme);
fixture.detectChanges();
expect(
fixture.nativeElement.querySelector(`[data-theme-leaf="${theme}"]`),
).toBeTruthy();
});
config ဘက်မှာလည်း သက်ဆိုင်ရာ test ရှိပါတယ်။ theme config တစ်ခုစီရဲ့ id field ဟာ config table ထဲက သူ့ရဲ့ key နဲ့ တူရပါမယ်။ CSS path တွေကလည်း family စည်းမျဉ်းနဲ့ ကိုက်ညီရပါမယ်။
ဒီစစ်ဆေးချက်နှစ်မျိုးပေါင်းလိုက်တာနဲ့ “sibling theme တွေထဲက တစ်ခုခုကျန်ခဲ့သလား” ဆိုတာကို လူက review လုပ်ရတဲ့အလုပ်ဟာ CI က တားဆီးပေးတဲ့ error ဖြစ်လာပါတယ်။ theme 100 ကျော်တဲ့အရွယ်အစားကို လူ့မျက်စိနဲ့ အကုန်စစ်ဖို့ မဖြစ်နိုင်ပါဘူး။
လက်ရှိသုံးနေတဲ့ theme CSS ကိုပဲ download လုပ်ပါ#
အလွှာခွဲခြားမှုက maintenance ပြဿနာကို ဖြေရှင်းပေးပေမယ့် theme အများကြီးရှိခြင်းကြောင့် user ကို တိုက်ရိုက်ထိခိုက်စေတဲ့ ကုန်ကျစရိတ်တစ်ခုလည်း ရှိပါတယ်- CSS ပါ။
မူလနည်းလမ်းမှာ theme stylesheet 136 ခုလုံးကို package တစ်ခုထဲ ထည့်ထားပါတယ်။ user က ဘယ် theme သုံးသုံး အားလုံးကို download လုပ်ပြီး parse လုပ်ရပါတယ်။ လိုအပ်သလို load လုပ်တဲ့နည်းကို ပြောင်းပြီးနောက် theme တစ်ခုတည်းရဲ့ resource ဟာ 2.4 MB ဝန်းကျင်ကနေ 17 KB အထိ လျော့ကျသွားပြီး 99% လောက် သက်သာလာပါတယ်။
လုပ်ဆောင်ပုံက ရိုးရှင်းပါတယ်။ theme config တစ်ခုစီမှာ ကိုယ်ပိုင် stylesheetHref ကို ကြေညာပြီး၊ တစ်ခုတည်းသော loader က စာမျက်နှာပေါ်က theme <link> တစ်ခုကို စီမံပါတယ်-
@Injectable()
export class ThemeStylesheetLoader {
readonly #document = inject(DOCUMENT);
load(href: ThemeAppearance['stylesheetHref']): void {
const id = 'case-study-theme-stylesheet';
const existing = this.#document.getElementById(id) as HTMLLinkElement | null;
const link = existing ?? this.#document.createElement('link');
link.id = id;
link.rel = 'stylesheet';
if (link.getAttribute('href') !== href) link.setAttribute('href', href);
if (!existing) this.#document.head.append(link);
}
}
platform က theme ပြောင်းတဲ့အခါ ဒီကို ခေါ်ပါတယ်-
effect(() => {
const appearance = THEME_APPEARANCES[this.selectedTheme()];
this.#stylesheetLoader.load(appearance.stylesheetHref);
});
“တစ်ခုတည်း” ဆိုတာ အဓိကပါ။ နေရာတိုင်းက ကိုယ်ပိုင် <link> ကို ထည့်နေကြရင် အကြိမ်ကြိမ်ပြောင်းပြီးနောက် theme အဟောင်းရဲ့ style တွေ ကျန်နေနိုင်သလို CSS ဖိုင်နှစ်ခုက တစ်ခုနဲ့တစ်ခု ထပ်ဖုံးနေနိုင်ပါတယ်။ အကြိမ်ကြိမ်ပြောင်းပြီးနောက် စာမျက်နှာပေါ်မှာ စီမံခန့်ခွဲထားတဲ့ stylesheet တစ်ခုတည်းပဲ ကျန်ကြောင်း test က စစ်ဆေးပေးပါတယ်။
theme CSS ကိုယ်တိုင်က design token (CSS variable) တွေကိုပဲ သတ်မှတ်ပြီး core ရဲ့ style တွေက အဲဒီ variable တွေကိုပဲ ဖတ်ပါတယ်-
:root {
--demo-surface: #fffaf1;
--demo-text: #3b2620;
--demo-accent: #c65367;
--demo-radius: 30px;
}
ဒါကြောင့် theme ပြောင်းတာက variable table တစ်ခုကို ပြောင်းတာပဲဖြစ်ပြီး core ရဲ့ style ကို လုံးဝပြင်စရာမလိုပါဘူး။ light/dark mode ကတော့ ဖိုင်တစ်ခုတည်းထဲက variable အုပ်စုနောက်တစ်ခုပါပဲ။
အပေးအယူများ#
ဒီ design ကို အခမဲ့ရတာ မဟုတ်ပါဘူး-
- ဖိုင်အရေအတွက် ပိုများလာပါတယ်။ theme တစ်ခုအတွက် leaf တစ်ခု၊ layout တစ်မျိုးအတွက် view တစ်ခု ရှိလာတဲ့အတွက် ဖိုင်ငယ်အရေအတွက် တိုးလာပါမယ်။ အကျိုးအမြတ်က ဖိုင်တစ်ခုချင်းစီရဲ့ တာဝန်ကို တစ်ချက်ကြည့်ရုံနဲ့ သိနိုင်ပြီး ပြည့်စုံမှုကို စစ်ဆေးနိုင်တာပါ။
- config ကို programming language တစ်ခုလို မဖြစ်စေပါနဲ့။ config က အသွင်အပြင်နဲ့ နယ်နိမိတ်သတ်မှတ်ထားတဲ့ ကွာခြားချက်တွေကို ဖော်ပြဖို့ သင့်တော်ပါတယ်။ config ထဲမှာ condition တွေ၊ flow တွေ စရေးလာပြီဆိုရင် မူလ if/else တွေကို တခြားနေရာမှာ ဝှက်ထားတာပဲ ဖြစ်ပါတယ်။
- core အတွက် ပိုခိုင်မာတဲ့ contract test တွေ လိုပါတယ်။ theme အားလုံးက ၎င်းကို အတူသုံးတဲ့အတွက် ပြင်ဆင်ချက်တစ်ခုက theme 100 ကျော်အပေါ် သက်ရောက်ပါတယ်။
- runtime မှာ CSS ပြောင်းဖို့ owner တစ်ဦးတည်း လိုပါတယ်။ ညှိနှိုင်းမှုမရှိတဲ့ stylesheet request တွေက ဖျတ်ခနဲပြောင်းလဲမှု ဒါမှမဟုတ် style ကျန်နေမှုကို ဖြစ်စေနိုင်ပါတယ်။ ဒါကြောင့် loader တစ်ခုတည်းပဲ ရှိဖို့ လိုတာပါ။
- cache က အရေးကြီးနေဆဲပါ။ theme တစ်ခုတည်းကိုပဲ load လုပ်ရင်တောင် တည်ငြိမ်တဲ့ file name နဲ့ cache header တွေက ပြန်လာတဲ့အခါ ဘယ်လောက်မြန်မလဲဆိုတာကို ဆုံးဖြတ်နေဆဲပါ။
ဘယ်အချိန်မှာ ဒီနည်းလမ်းကို သုံးသင့်သလဲ#
သင့် product မှာ light/dark mode နှစ်မျိုးပဲရှိရင် CSS variable တွေနဲ့ လုံလောက်ပြီး ဒီဖွဲ့စည်းပုံတစ်ခုလုံး မလိုအပ်ပါဘူး။
ဒီလိုအခြေအနေတွေ စကြုံလာပြီဆိုရင်တော့ စဉ်းစားသင့်ပါတယ်-
- theme ဒါမှမဟုတ် customer version ဆယ်ခုကျော်ရှိပြီး ဆက်တိုးနေတယ်။
- theme တွေကြားက ကွာခြားချက်ဟာ အရောင်တင်မဟုတ်ဘဲ layout၊ feature toggle နဲ့ စာသားတွေပါ ပါတယ်။
- theme တစ်ခုအတွက် လိုအပ်ချက်ကို ပြင်တိုင်း အခြား theme တစ်ခုကို မမျှော်လင့်ဘဲ ထိခိုက်စေတတ်တယ်။
- theme အသစ်ထည့်တဲ့အခါ ဘယ်နေရာတွေမှာ ဖြည့်စွက်ရမလဲဆိုတာ ဘယ်သူမှ မသေချာနိုင်ဘူး။
အထောက်အထား၏ နယ်နိမိတ်#
ဒီဆောင်းပါးမှာ ဖော်ပြထားတဲ့ production ကိန်းဂဏန်းတွေရဲ့ အကျုံးဝင်မှုကို ရှင်းလင်းဖို့ လိုပါတယ်-
- 23 လိုင်း ဆိုတာ refactor ပြီးနောက် ကိုယ်စားပြုနိုင်တဲ့ ပြည့်စုံတဲ့ theme leaf တစ်ခုရဲ့ အရေအတွက်ပါ။ leaf တိုင်း၊ ဖိုင်တိုင်း 23 လိုင်းရှိတယ်လို့ ဆိုလိုတာ မဟုတ်ပါဘူး။
- အဲဒီ migration မှာ architecture အသစ်ရဲ့ module 70 ခု ထည့်သွင်းခဲ့ပါတယ် (facade 24 ခု၊ data service 10 ခု၊ theme config 10 ခု၊ shared view 26 ခု)။ ဒါက ပြုပြင်ပြောင်းလဲမှုရဲ့ အကျယ်အဝန်းကို ဖော်ပြတာဖြစ်ပြီး performance တိုးတက်မှု ဒါမှမဟုတ် code လျှော့ချနိုင်မှုရလဒ် မဟုတ်ပါဘူး။
- 2.4 MB → 17 KB က production မှာ တိုင်းတာထားတဲ့ ရလဒ်ပါ။ public Demo ထဲက CSS သုံးဖိုင်အသေးတွေနဲ့ ဒီကိန်းဂဏန်းကို ပြန်မရနိုင်ပါဘူး။
- တူညီတဲ့ quality project ထဲမှာ အဓိကတိုင်းတာတဲ့ စာမျက်နှာရဲ့ Lighthouse Performance က 50+ ကနေ 90+ အထိ တိုးတက်ခဲ့ပါတယ်။ ဒါပေမယ့် အဲဒါဟာ တိုးတက်မှုအမျိုးမျိုးပေါင်းစုပြီး ရလာတာဖြစ်ပြီး CSS ကို လိုအပ်သလို load လုပ်တာတစ်ခုတည်းကြောင့် မဟုတ်ပါဘူး။
public repo က architecture mechanism ကိုယ်တိုင်ကို သက်သေပြပါတယ်။ type ပါတဲ့ contract၊ runtime မှာ ပြောင်းလဲခြင်း၊ theme family ပြည့်စုံမှုစမ်းသပ်ချက်၊ လိုအပ်သလို CSS load လုပ်ခြင်းနဲ့ ဒီစစ်ဆေးချက်တွေကို run တဲ့ CI တို့ပါဝင်ပါတယ်။ ပြောဆိုချက်တွေနဲ့ သက်ဆိုင်ရာအထောက်အထားတွေကို တွဲပြထားတဲ့ဇယား အပြည့်အစုံကို repo ရဲ့ အထောက်အထားနယ်နိမိတ် စစ်ဆေးမှု မှာ ကြည့်နိုင်ပါတယ်။
ရလဒ်ကို တိုက်ရိုက်ကြည့်ချင်ရင် အွန်လိုင်း Demo ကိုဖွင့်ပြီး theme သုံးခု၊ ဘာသာစကားနဲ့ light/dark mode ကို ပြောင်းကြည့်ပါ။ ပြီးရင် GitHub ပေါ်က source code နဲ့ နှိုင်းယှဉ်ကြည့်နိုင်ပါတယ်။