မဂၤလာပါ။
ကြၽန္ေတာ္ကေတာ့ Spiceworks Myanmar မွာ Backend Developer အေနနဲ႔ တာဝန္ယူလုပ္ကိုင္ေနတဲ့ သုတယာမိုး ျဖစ္ပါတယ္။ ဒီတစ္ေခါက္မွာေတာ့ Nuxt.js ရဲ႕ plugin တစ္ခုျဖစ္တဲ့ Nuxt Content အေၾကာင္းကို ေဝမွ်ေပးသြားခ်င္ပါတယ္ ခင္ဗ်။
What is Nuxt Content?
Nuxt Content ကေတာ့ .md, .yml, .csv, .json အစရွိတဲ့ local ဖိုင္မ်ားကို အသုံးျပဳၿပီး database မလိုအပ္ပဲ မိမိလိုခ်င္တဲ့ blog content မ်ားကို ျပဳလုပ္နိင္ေစတဲ့ file-based CMS တစ္ခု ျဖစ္ပါတယ္။ File အတြင္း မိမိလိုခ်င္ေသာ ေနရာတြင္ Vue Component မ်ားကို အသုံးျပဳႏိုင္ျခင္း၊ မိမိလိုခ်င္ေသာ blog content မ်ားကို query မွ တစ္ဆင့္ အလြယ္တကူ ေခၚယူအသုံးျပဳႏိုင္ျခင္း၊ document တစ္ခုစီတိုင္းမွာ REST API က built-in ပါဝင္ေနျခင္း အစရွိတာေတြကေတာ့ Nuxt Content က support လုပ္ေပးတဲ့ နည္းပညာမ်ား ျဖစ္ပါတယ္။
How to Install Nuxt Content?
Install လုပ္မည္ဆိုပါက
npx nuxi init content-app -t content npm install or yarn install npm run dev or yarn dev
ကို အသုံးျပဳ၍ install ျပဳလုပ္ႏိုင္ပါတယ္။ Install ျပဳလုပ္ၿပီးပါက Fig.(1) ကဲ့သို႔ folder structure ရရွိမွာျဖစ္ပါတယ္။ Nuxt Content မွာ အဓိက အသုံးျပဳမယ့္ directory ေတြကေတာ့ pages, content, public နဲ႔ components directory တို႔ပဲျဖစ္ပါတယ္။

pages directory မွာကေတာ့ application views နဲ႔ routes တို႔ပါဝင္မွာျဖစ္ပါတယ္။ pages directory file တစ္ခု create လုပ္႐ုံနဲ႔႔ nuxt.js က router configuration ကို အလိုလို generate လုပ္ေပးမွာျဖစ္ပါတယ္။ “npm run dev” ကို run လိုက္ပါက “http://localhost:3000” ဆိုတဲ့ url ကိုရရွိမွာျဖစ္ပါတယ္။ တစ္သတ္မွတ္တည္းရွိေနမယ့္ route မ်ား (static routes) ကို create လုပ္ခ်င္ရင္ pages/about.vue, pages/contact.vue စသျဖင့္ create ျပဳလုပ္ႏိုင္ပါတယ္။ ထိုအခါ “http://localhost:3000/about”, ”http://localhost:3000/contact” ဟူ၍ static routes မ်ားကို auto-generate လုပ္ေပးသြားမွာျဖစ္ပါတယ္။ http://localhost:3000/1, http://localhost:3000/2 အစရွိတဲ့ ေျပာင္းလဲမႈရွိႏိုင္တဲ့ route မ်ား (dynamic routes) ကို create လုပ္ခ်င္ရင္ေတာ့ pages/[id].vue, pages/[slug].vue စသျဖင့္ create ျပဳလုပ္ႏိုင္ပါတယ္။
content directory မွာကေတာ့ မိမိေရးခ်င္တဲ့ blog content ေတြကို markdown, json, yml, csv အစရွိတဲ့ file type အမ်ိဳးမ်ိဳးကို အသုံးျပဳကာ create လုပ္ႏိုင္မယ့္ directory ျဖစ္ပါတယ္။

Image မ်ားကိုသိမ္းဖို႔အတြက္ public/img/ directory ကို create လုပ္ေပးရမွာျဖစ္ပါတယ္။ public directory က built-in မပါဝင္တဲ့အတြက္ ကိုယ္တိုင္ create လုပ္ေပးရန္ လိုအပ္ပါတယ္။
components directory မွာေတာ့ blog content ေရးမယ့္ file ေတြထဲမွာ မိမိအသုံးျပဳခ်င္တဲ့ ဥပမာ alert.vue, tooltip.vue အစရွိတဲ့ vue components ေတြကို ထားရွိရမယ့္ directory ျဖစ္ပါတယ္။ components directory ကလည္း built-in မပါဝင္တဲ့အတြက္ ကိုယ္တိုင္ create လုပ္ေပးရန္ လိုအပ္ပါတယ္။ vue components ေတြကို components/content/ directory ေအာက္မွာ create လုပ္ေပးရမွာျဖစ္ပါတယ္။
How to write blog content?

Blog Content ေတြကို content/ directory ထဲမွာ မိမိေရးခ်င္တဲ့ file အမ်ိဳးအစားကို အသုံးျပဳၿပီး ေရးႏိုင္ပါတယ္။ Fig. (3) မွာေတာ့ /content/pokemons/ directory ထဲက charizard.md file ျဖစ္ပါတယ္။ charizard.md အတြင္းမွာပါဝင္တဲ့ content မ်ားရဲ႕ ဆိုလိုရင္းေတြကေတာ့ ေအာက္ပါအတိုင္းျဖစ္ပါတယ္။
--- title: 'Charizard' info: 'Info of Charizard' ---
မိမိလိုခ်င္တဲ့ content ပါဝင္သည့္ file မ်ားကို query နဲ႔ ရွာေဖြရလြယ္ေအာင္ လုပ္ေပးႏိုင္မယ့္ variable မ်ားကို file ရဲ႕ ထိပ္ဆုံး — — အတြင္းေရးေပးရမွာ ျဖစ္ပါတယ္။
# Charizard
content ကို heading tag အျဖစ္ေဖာ္ျပလိုပါက # ကို အသုံးျပဳေပးရမွာျဖစ္ပါတယ္။
::alert{type=success}
alert box
::

components/content/ directory ထဲက vue component ေတြကိုေခၚသုံးလိုတဲ့အခါ :: :: အတြင္းေရးေပးရမွာ ျဖစ္ပါတယ္။ vue component ထဲကို props အေနနဲ႔ data ေတြကိုေပးပို႔လိုတဲ့အခါမွာ တြန္႔ကြင္း {} အတြင္းေရးေပးရမွာျဖစ္ပါတယ္။ ဥပမာပါတဲ့ ::alert ကေတာ့ /components/content/Alert.vue component ကို ဆိုလိုတာျဖစ္ပါတယ္။ Alert.vue, Card.vue စသျဖင့္ ထိပ္ဆုံး စကားလုံးကို အႀကီးျဖင့္ေရးေပးရမွာ ျဖစ္ပါတယ္။
(link)[/pokemon]
Link မွာ ျပခ်င္တဲ့စာသားကို ေလးေထာင့္ကြင္း [] အတြင္းေရးေပးရမွာျဖစ္ၿပီး ကိုယ္သြားခ်င္တဲ့လမ္းေၾကာင္းကိုေတာ့ လက္သည္းကြင္း () အတြင္းေရးေပးရမွာ ျဖစ္ပါတယ္။

ေလးေထာင့္ကြင္း [] အတြင္းမွာ image title ကိုေရးေပးရမွာျဖစ္ၿပီး image ရွိေနတဲ့ လမ္းေၾကာင္းကိုေတာ့ လက္သည္းကြင္း () အတြင္းေရးေပးရမွာ ျဖစ္ပါတယ္။
> Block quote
content ကို blockquote tag အျဖစ္ေဖာ္ျပလိုပါက > ကို အသုံးျပဳေပးရမွာျဖစ္ပါတယ္။
```javascript
export default () => {
console.log(‘code block’)
}
```
content ကို code HTML Tag အျဖစ္ေဖာ္ျပလိုပါက “` “` ကို အသုံးျပဳေပးရမွာျဖစ္ပါတယ္။ charizard.md file ကို Browser မွာ run လိုက္ပါက Fig. (5) ပုံစံရရွိမွာျဖစ္ပါတယ္။

How to create a blog using Nuxt Content?
Nuxt content ကို အသုံးျပဳၿပီး blog ဘယ္လိုေရးရမလဲ ဆိုတာကိုေတာ့ Pokemon blog ေလးတစ္ခုေရးၿပီး ရွင္းျပေပးသြားခ်င္ပါတယ္။ အခု blog မွာေတာ့ url (3) ခုသာပါရွိမွာျဖစ္ပါတယ္။ http://localhost:3000 (Home Page), http://localhost:3000/pokemon (All Pokemons Page) ႏွင့္ http://localhost:3000/pokemon/:slug (Pokemon Detail Page) တို႔ပဲျဖစ္ပါတယ္။

ထို page မွတစ္ဆင့္ All Pokemons ဆိုတဲ့ button ကိုႏွိပ္ပါက All Pokemons Page သို႔ေရာက္ရွိမွာျဖစ္ပါတယ္။ ထို page မွာေတာ့ /content/pokemons/ directory ထဲက blog content မွန္သမွ်ကို ေဖာ္ျပသြားမွာျဖစ္ပါတယ္။

Document ေတြကို တစ္ခုထက္ပိုၿပီး fetch လုပ္ခ်င္တဲ့အခါမွာ “ContentList” component ကိုအသုံးျပဳေပးရမွာျဖစ္ပါတယ္။ ကြၽန္ေတာ္ကေတာ့ /content/pokemons/ directory ေအာက္က document ေတြကိုလိုခ်င္တဲ့အတြက္ေၾကာင့္ “ContentList” ကိုအသုံးျပဳထားတာ ျဖစ္ပါတယ္။ path=“/pokemons” ကေတာ့ /content/pokemons/ directory ေအာက္က document ေတြကိုလိုခ်င္တဲ့အတြက္ အသုံးျပဳထားတာျဖစ္ပါတယ္။ အကယ္၍ content directory ေအာက္ကေနပဲ လိုခ်င္တယ္ဆိုရင္ေတာ့ path=“/“ လို႔ေရးေပးရမွာျဖစ္ပါတယ္။ “ContentList” မွာ default props အေနနဲ႔ ရရွိမွာေတြကေတာ့ path နဲ႔ query ျဖစ္ၿပီးေတာ့ list ကေတာ့ default slots အေနနဲ႔ရရွိမွာျဖစ္ပါတယ္။ “ContentList” ကို အသုံးမျပဳဘဲ Fig.(8) ကဲ့သို႔ queryContent() ကိုအသုံးျပဳကာ single document, multiple documents ေတြကို fetch လုပ္ႏိုင္ပါတယ္။

queryContent() ကေတာ့ script tag အတြင္းေရးေပးရမွာ ျဖစ္ပါတယ္။ သူ႔မွာလည္း “ContentList” မွာကဲ့သို႔ /content/pokemons directory ေအာက္က document ေတြကိုလိုခ်င္ရင္ queryContent(“/pokemons”)၊ content/ ေအာက္ကလိုခ်င္ရင္ queryContent(“/pokemons”) ဟုေရးေပးရမွာျဖစ္ပါတယ္။ find() ကေတာ့ document အကုန္လုံးကို ယူေပးပါလို႔ ဆိုလိုတာျဖစ္ပါတယ္။ findOne() ဆိုရင္ေတာ့ document တစ္ခုထဲကိုသာယူေပးပါလို႔ ဆိုလိုတာျဖစ္ပါတယ္။ Fig.(9) ကေတာ့ “ContentList” နဲ႔ queryContent() တစ္ခုခုကို အသုံးျပဳၿပီး run လိုက္တဲ့အခါမွာ ရရွိလာမယ့္ result ျဖစ္ပါတယ္။

ထိုမွတစ္ဆင့္ “gotodetail” ဆိုတဲ့ link ကိုႏွိပ္ပါက Pokemon Detail Page သို႔ေရာက္ရွိမွာျဖစ္ပါတယ္။

“ContentRenderer” component ကေတာ့ queryContent() ကေနမွ ရရွိလာတဲ့ data ကိုမွ တစ္ဆင့္ယူၿပီး ေဖာ္ျပေပးတဲ့ component ျဖစ္ပါတယ္။ /content directory ထဲမွ .md, .json အစရွိတဲ့ file ရဲ႕ content ကိုလိုခ်င္တဲ့အခါမွာ “ContentRendererMarkdown” ကိုအသုံးျပဳေပးရမွာျဖစ္ပါတယ္။
queryContent('pokemons').where({ slug: route.params.slug[0] }).findOne()
where({ slug: route.params.slug[0] }) ကေတာ့ url မွာပါလာတဲ့ slug နဲ႔ Fig.(3) ရဲ႕ — — အတြင္းမွာ ေၾကညာထားတဲ့ variable slug နဲ႔ တူညီတဲ့ file ကိုယူေပးပါလို႔ဆိုလိုတာျဖစ္ပါတယ္။
queryContent('pokemons').only(["_path", "title", "description","slug"]).sort({ date: 1 }).findSurround(`/pokemons/${route. params.slug[0]}`)
only([“_path”, “title”, “description”,”slug”]) ကေတာ့ — — အတြင္းမွာ ေၾကညာထားတဲ့ variable ေတြထဲကမွ ကိုယ္လိုခ်င္တဲ့ variable ကိုပဲလိုခ်င္တဲ့အခါ အသုံးျပဳပါတယ္။
.sort({ date: 1 }) ကေတာ့ file ေတြကို create လုပ္တဲ့ရက္နဲ႔ ငယ္စဥ္ႀကီးလိုက္ စီေပးတာျဖစ္ပါတယ္။ ႀကီးစဥ္ငယ္လိုက္ လိုခ်င္ရင္ေတာ့ .sort({ date: -1 }) ဟုေရးေပးရမွာျဖစ္ပါတယ္။
findSurround(`/pokemons/${route.params.slug[0]}`) ကေတာ့ ကိုယ္လိုခ်င္တဲ့ file ရဲ႕ အေပၚေအာက္ file ႏွစ္ခုကိုရယူလိုတဲ့အခါ အသုံးျပဳရမွာျဖစ္ပါတယ္။ Fig.(5) ကေတာ့ Fig.(10) က code ကို run လိုက္တဲ့အခါမွ ရရွိတဲ့ result ျဖစ္ပါတယ္။
ကြၽန္ေတာ္ မွ်ေဝေပးခဲ့တဲ့အထဲမွာ မပါဝင္တဲ့ အျခားေသာအရာေတြကို ေလ့လာခ်င္ရင္ေတာ့ https://content.nuxtjs.org/ မွာ ဆက္လက္ေလ့လာသြားဖို႔ တိုက္တြန္းလိုပါတယ္။
အဆုံးထိ အခ်ိန္ေပးၿပီး ဖတ္ေပးတဲ့အတြက္ ေက်းဇူးတင္ပါတယ္ ခင္ဗ်။
