Gerege v2 / next.js + headless wordpress + erxes /
Features
next, react, sass, typysecript, apollo , graphql
Install хийхийн өмнө хийх гэж байгаа вебийн Wordpress-ээ Sys admin-д хэлж үүсгүүлээд, нэвтрэх access-аа авч Wpgraphql plugin суулгаж env дээрээ холбохгүй бол Error: Only absolute URLs are supported гэсэн алдаа гарна.
Гарчиг
Install
-
git clone git@github.com:nmgteam/gerege.git
-
cd gerege
-
cp .env.sample .env .env file үүсгээд дотор нь Wpgraphql url - аа холбож өнгө. // e.g : https://rio.nmma.co/wp/graphql
-
NEXT_PUBLIC_WORDPRESS_API_URL=[wp url]/graphql
-
NEXT_PUBLIC_ERXES_API_URL=[erxes url] erxes-тэй холбохгүй бол шаардлагагүй.
-
cp static/js/window.env.sample.js static/js/window.env.js
-
yarn install
-
yarn dev
Styling
SASS
-
Yarn install хийх үед SASS суусан байгаа
-
pages/_app.js дотор import хийсэн style бүх pages болон component дээр ажиллах учраас global style-уудаа энд import хийнэ.
pages/_app.js дотор node_modules-аас хүссэн style-аа import хийж оруулж ирэх боломжтой учраас хэрэглэж байгаа сангийнхаа style-ийг import хийж оруулж ирнэ. Жишээ нь:
import 'rsuite/lib/styles/index.less';
import 'swiper/swiper.less';
import '../styles.css';
-
гэх мэт байдлаар.
NextJs .module.scss эсвэл .module.sass өргөтгөл ашиглан Component-ын түвшинд боломжтой. Тиймээс тухайн component дотор [componentName].module.sass гэж нэрлээд ашиглана. Автоматаар өөрөө unique className өгдөг учраас ижил className өгсөн ч асуудалгүй ажиллана. Жишээ нь: Button.module.scss file
.error {
color: white;
background-color: red;
}
Button component
import styles from './Button.module.scss';
export function Button() {
return (
<button
type="button"
// Note how the "error" class is accessed as a property on the imported `styles` object.
className={styles.error}
>
Destroy
</button>
);
}
-
Энэ error class бусад error class-тай давхцахгүй ажиллана.
Styled Components
Хэрвээ Styled Components ашиглах бол дараах тохиргоог next.config.js file дээр дараах тохиргоог хийнэ.
module.exports = {
compiler: {
// ssr and displayName are configured by default
styledComponents: true,
},
};
Wp plugins
-
*Wpgraphql - Wordpress-ээсээ data - г graphql - р авахын тулд уг plugin - г суулгаж өгнө.
-
*Wp GraphQL Offset Pagination - pagination нэмнэ /stable version - ий .zip file-ийг татна уу! /
-
Advanced Custom Fields - нэмэлт field
-
WPGraphQL for Advanced Custom Fields ACF дээрх field - н data - гаа graphql - р авахийн тулд
-
-
Polylang - олон хэлтэй сайтад
-
Headless mode - WP - н front руу орох боломжийг хааж, хийж байгаа вебрүүгээ redirect хийх боломж олгоно.
Wp data fetching
src/data/wp/ Data fetch хийхэд ихэнх тохиолдолд хэргэлдэг ready-to-use функцууд:
-
getPaginatedPosts(currentPage, slug)
-
getAllPosts()
-
getPostsByCategory(slug, search, order)
-
getPostBySlug(slug)
-
getAllMenus()
-
getPageBySlug(slug)
-
getPagesByParent(databaseId)
Мөн дээрх функцуудээс гадна нэмээд Wpgraphql-ээ харж байгаад query-ээ бичээд вебийнхээ шаардлаганд нийцсэн датаг авах боломжтой.
Жишээ:
//postiin detailiig [slug]-r ni avaad props - r damjuulj baigaa code.
export async function getStaticProps({ params = {} as any } = {}) {
const { post } = await getPostBySlug(params.slug);
return {
props: {
post,
},
};
}
export async function getStaticPaths() {
const { posts } = await getAllPosts();
return {
paths: posts.map((post) => `/posts/${post.slug}`) || [],
fallback: false,
};
}
Wordpress Menu Fetching
-
Layout дээрээ menu-гээ дуудаж өгнө.
// _app.tsx
MyApp.getInitialProps = async function (appContext: any) {
const appProps = await NextApp.getInitialProps(appContext);
const { menu } = await getMenu('Main menu'); // Wp deerh menunii ner
return {
...appProps,
menu,
};
};
const getLayout = Component.getLayout || ((page: any) => <Layout menu={menu}>{page}</Layout>);
-
Ирж буй menu-гээ хэвлэхдээ
{
menu &&
menu.menuItems.nodes.map(
(item: any) =>
item.parentId === null && (
<div key={item.id} className={`menu-item`}>
<Link href={item.path}>
<a>{item.label}</a>
</Link>
{item.childItems.edges.length > 0 && (
<div className="dropdown">
{item.childItems.edges.map((child: any) => (
<Link key={child.node.id} href={child.node.url}>
<a>{child.node.label}</a>
</Link>
))}
</div>
)}
</div>
)
);
}
SEO
Wordpress
post, page - н дэлгэрэнгүй дээр /src/components/common/seo компонентыг дуудаж өгөөд post props-руу ирж байгаа post-оо явуулах ёстой. Хэрвээ Нүүр хуудас дээр байгаа бол default - р Wordpress General settings - н Site Title, Tagline - г meta tag дээр харуулж байгаа.
Erxes
erxes - с ирж байгаа датанууд бүгд Client-Side rendering хийж /modules - с датагаа авж байгаа болохоор SEO дээр хүндрэл гардаг. Зөвхөн detail (e.g. product) хуудсан дээр next page - н getStaticProps, getServerSideProps дотор getErxesApolloClient ашиглаад датагаа prerender хийж аваад SEO component -руугаа дамжуулж болно.
Жишээ:
export async function getStaticProps() {
const apolloClient = getErxesApolloClient();
const { data } = await apolloClient.query({
query: gql(productDetailQuery),
variables: {
id,
},
});
const product = data?.productDetail || {};
return {
props: {
product,
},
};
}
Multi-Language
-
next.config.js дээрээ i18n тохиргоо хийнэ.
// next.config.js
module.exports = {
i18n: {
locales: ['en-US', 'mn'], //geh met busad helee nemne.
defaultLocale: 'en-US',
},
};
-
Дээр дурдсан - Polylang plugin - г Wordpress дээрээ суулгаж хэлүүдээ тохиргоон дээрээ нэмээд агуулгаа оруулна. Дараа нь , WP GraphQL Polylang plugin суулгаад query - дээрээ translation гэсэн Field нэмнэ.
Жишээ
// src/data/wp/queries/posts.ts
export const QUERY_POSTS_BY_CATEGORY_SLUG = gql`
query PostsByCategoryId($categorySlug: String!, $lang: LanguageCodeEnum!) {
posts(where: { categoryName: $categorySlug }) {
edges {
node {
translation(language: $lang) {
id
categories {
edges {
node {
databaseId
id
name
slug
}
}
}
content
date
excerpt
featuredImage {
node {
altText
caption
id
sizes
sourceUrl
srcSet
}
}
}
}
}
}
}
`;
-
Data дуудаж байгаа функц дээрээ locale parameter дамжуулж өгнө.
// src/data/wp/posts.js
export async function getPostsByCategory(slug, locale) {
const apolloClient = getApolloClient();
const data = await apolloClient.query({
query: QUERY_POSTS_BY_CATEGORY_SLUG,
variables: { categorySlug: slug, lang: locale ? locale.toUpperCase() : 'EN' },
});
const posts = data?.data.posts.edges.map(({ node = {} }) => node);
return {
posts: Array.isArray(posts) && posts.map(mapPostData),
};
}
-
Data-гаа харуулахдаа доорх байдлаар бичиж өгнө.
<h6>{post.translation.title}</h6>
<div dangerouslySetInnerHTML={{ __html: post.translation.content }} />
//getstaticprops
export async function getStaticProps(context) {
const posts = await getPostsByCategory('news', context.locale);
return {
props: {
posts
},
revalidate: 60,
};
}
Web дээрх статик текстүүдээ орчуулахийн тулд доорх алхамаар явна.
-
yarn add next-translate
-
next.config.js дээрээ доорх кодыг нэмж өгнө.
const nextTranslate = require('next-translate');
module.exports = nextTranslate({
i18n: {
locales: ['en', 'mn'], //geh met busad helee nemne.
defaultLocale: 'en',
},
});
-
root directory дээрээ i18n.js гэсэн файл үүсгээд доорх кодыг нэмж өгнө.
module.exports = {
locales: ['en', 'mn'],
defaultLocale: 'en',
pages: {
'*': ['common'],
},
};
-
/locales гэсэн хуудас root directory дээрээ үүсгээд доор заасаны дагуу зохион байгуулна.
├── mn
│ ├── common.json
├── en
│ ├── common.json
└── cn
├── common.json
// en/common.json
{
"title": "Hello world",
}
// mn/common.json
{
"title": "сайн уу ертөнц",
}
-
Орчуулгаа хэвлэхдээ
import useTranslation from 'next-translate/useTranslation';
export default function ExamplePage() {
const { t } = useTranslation('common');
return <div>{t('title')}</div>; // hello world
}
Дэлгэрэнгүй: https://www.npmjs.com/package/next-translate#1-about-next-translate
Next/image
next/image нь зургыг .webp(web-т зориулсан зургийн хамгийн хөнгөн өргөтгөл) руу хувиргаад .next/cache/images folder-т хадгалдаг. Мөн зургын хэмжээ чанарыг оptimize хийдэг.
next.config.js дээр зургын домайныг оруулж өгнө
module.exports = {
images: {
domains: ['example.com', 'example2.com'],
},
};
Жишээ:
import Image from 'next/image';
<div className="img-wrap">
{' '}
// layout="fill" aшиглаж байгаа тохиолдолд parent element нь position="relative" style тай байх ёстой
<Image
src={'/images/logo-bg.png'} //src
alt={detail.name} // alt
objectFit="contain" //contain || cover
layout="fill" // next/image aшиглахад өндөр, өргөн эсвэл layout="fill" нэмэхийг шаарддаг. layout="fill" нь зураг parent element-ee дүүргэдэг болгоно.
/>
</div>;
давуу тал:
-
Lazy load
-
image optimization
-
CLS( cumulative layout shift) зураг гарч ирэхдээ вэб дээр хөдөлгөөн үүсгэхгүй
бусад property:
-
priority : logo зэрэг байнга харагдаж байх ёстой зурагнууд дээр тавьж өгнө. Ингэснээр тухайн зурагнуудыг цаанаа head tag дотор вэб load хийх үед дуудаж өгдөг болохоор олон газар бичвэл вэб удаан болно.
-
quality : default нь 75 байдаг. зурагын чанарыг 1-100 хооронд тохируулж болно
components/common/Image.tsx ийн loading transition нэмсэн байгаа бусдаар яг адилхан. Дуудаж ашигласан жишээ _error.tsx page-ээс харж болно
Дэлгэрэнгүй: https://nextjs.org/docs/basic-features/image-optimization
Erxes
Erxes query
-
import { gql, useQuery} from '@apollo/client';Компонент дотор ашиглах санг оруулж ирнэ.
-
import { queries } from '../graphql'; Өөрийн бичиж үүсгэсэн query дундаас ашиглах Query - ыг оруулж ирнэ.
-
import { getErxesApolloClient } from '../../../lib/initApollo';Apollo тохиргоо хэсгийг оруулж ирнэ. Энэ хэсэгт API url болоод бусад нэмэлт хэсгүүд байна. Жишээ нь access token хадгалах, header дээр талбар нэмэх.
const { data, loading } = useQuery(gql(queries), {
variables: { ...args, clientPortalId: getEnv('NEXT_PUBLIC_CP_CONFIG_ID') }
fetchPolicy: 'network-only',
client: getErxesApolloClient()
});
variables -т уг query-д ашиглагдах утгуудыг JSON байдлаар өгнө. data-д API -аас ирсэн хариу байна. loading API -аас хариу ирэх хүртэл true бусад үед false байна.
Erxes Mutation
-
import { gql, useMutation } from '@apollo/client'; Компонент дотор ашиглах санг оруулж ирнэ.
-
import { mutations } from '../graphql'; Өөрийн бичиж үүсгэсэн mutation дундаас ашиглах mutaion - ыг оруулж ирнэ.
-
import { getErxesApolloClient } from '../../../lib/initApollo'; Apollo тохиргоо хэсгийг оруулж ирнэ. Энэ хэсэгт API url болоод бусад нэмэлт хэсгүүд байна. Жишээ нь access token хадгалах, header дээр талбар нэмэх.
const [loginMutation] = useMutation(gql(mutations), { client: getErxesApolloClient() });
login Mutation гэсэн функц үүсгэснээр доор ашиглахад хялбар цэгцтэй.
loginMutation({
variables: {
...args,
clientPortalId: getEnv('NEXT_PUBLIC_CP_CONFIG_ID'),
},
})
.then((response) => {
console.log('successfully login');
router.push('/');
})
.catch((e) => {
console.log('error: ', e.message);
});
-
variables -т уг mutation-д ашиглагдах утгуудыг JSON байдлаар өгнө. .then API аас хариу амжилтай ирвэл энэ хэсэгт байх код ажиллана. .catch API аас ирсэн хариу алдаатай бол энэ хэсэгт байх код ажиллана.
erxes дээр автомат өгөгдөл үүсгэх
Та erxes/api дотор ороод доорх command-ыг хийснээр erxes-ын localhost-д нэвтрэх mail болон password-ыг авах боломжтой.
yarn loadTestData
Cloudflare Workers дээр react сайт байршуулах
Заавар 1.
- Terminal дээр react прожект дотроо npm install хийх
- Terminal дээр react прожект дотроо wrangler init --site коммандыг ажиллуулах
- Terminal дээр прожект дотроо vim коммандаар wrangler.toml файлаа нээх
Заавар 2.
- Cloudflare Workers рүүгээ нэвтэрч орох
- Account id-гаа copy-дож аваад wrangler.toml файл дотор Account id дээрээ paste хийж өгөх
- Wrangler.toml файлын Bucket дээр нь ./build гэж бичээд :wq дарж хадгалах
- Үүний дараа npm run build комманд бичиж ажиллуулах
- Terminal дээрээ wrangler publish коммандаар прожектоо publish хийх
Нэмэлт: Тухайн сайт workers.dev гэсэн subdomain дээр үүснэ.