ตัวอย่างสด (live preview)
หน้านี้สอนอะไร
ให้ผู้แก้เห็นหน้าเว็บจริงข้างฟอร์ม อัปเดตตามที่พิมพ์ก่อนบันทึก
ควรอ่านก่อน: ฉบับร่าง เวอร์ชัน และการตั้งเวลา

ผู้แก้ไขเห็นหน้าเว็บจริงอยู่ข้างฟอร์ม และหน้านั้นอัปเดตตามที่พิมพ์ทันทีโดยยังไม่ต้องบันทึก
{
slug: 'posts',
preview: ({ doc }) => (doc.slug ? `/posts/${doc.slug}` : null),
fields: [/* … */],
}preview คืนค่าหน้าที่แสดงเอกสารนั้น เป็น path บนเว็บหรือ URL แบบเต็ม หรือ null ถ้าเอกสารไม่มีหน้า global ใช้ option เดียวกันได้ จากนั้นหน้า admin จะมีปุ่ม Preview ซึ่งเปิดหน้าเว็บใน frame ข้างฟอร์ม
ทำงานอย่างไร
- หน้า admin โหลดหน้าจาก
previewครั้งเดียว - ทุกครั้งที่ฟอร์มเปลี่ยน admin จะส่งข้อมูลในฟอร์มไปที่ server (
POST /:collection/:id/preview) ซึ่งคืน เอกสารในรูปแบบเดียวกับการอ่านปกติ คือ populate relationship และไฟล์อัปโหลด และรัน hookafterReadแล้ว โดยไม่บันทึกอะไร - admin ส่งเอกสารนั้นไปให้หน้าเว็บด้วย
postMessageแล้วหน้าเว็บ render ใหม่
ดังนั้นหน้าเว็บต้อง render จากเอกสารที่ได้รับ helper ด้านล่างช่วยเชื่อมส่วนนี้ให้
Nuxt
useLivePreview ถูก auto-import ให้แล้ว ส่ง ref ที่เก็บเอกสารให้มัน:
<script setup lang="ts">
import { renderRichText } from '@easy-cms/richtext'
const { data: post } = await useFetch(`/api/posts/${useRoute().params.slug}`)
useLivePreview(post)
const html = computed(() => renderRichText(post.value?.body))
</script>Next.js
โหลดข้อมูลใน Server Component แล้ว render ใน Client Component ด้วย useLivePreview:
'use client'
import { useLivePreview } from '@easy-cms/next/live-preview'
export function PostView({ post: initial }: { post: Post }) {
const post = useLivePreview(initial)
return <h1>{post.title}</h1>
}Frontend อื่นๆ
import { subscribeLivePreview } from '@easy-cms/core/live-preview'
const stop = subscribeLivePreview((doc) => render(doc), {
origin: 'https://cms.example.com', // the admin's origin; default: the page's own
})นอก frame ของหน้า admin helper เหล่านี้ไม่ทำอะไร จึงปล่อยไว้ในโค้ด production ได้
Preview token
เมื่อหน้า admin เปิดตัวอย่าง จะเติม easy-cms-preview=<token> ต่อท้าย URL token นี้เปิดอ่าน ฉบับร่างปัจจุบัน ของเอกสารเดียว (หรือ global เดียว) ได้ 1 ชั่วโมงโดยไม่ต้องเข้าสู่ระบบ frontend ที่อยู่คนละ origin จึงแสดง ฉบับร่างที่ยังไม่เคยเผยแพร่ได้:
import { getPreviewToken } from '@easy-cms/core/live-preview'
const token = getPreviewToken() // from ?easy-cms-preview=, or null
const post = await fetch(
`${api}/posts/${id}?depth=2${token ? `&preview=${token}` : ''}`,
).then((r) => r.json())กรณีนี้ให้ใส่ id ของเอกสารไว้ใน URL ของ preview เช่น preview: ({ doc }) => \https://www.example.com/preview/posts/${doc.id}\``
ฝั่ง server cms.verifyPreviewToken(token) คืนสิ่งที่ token เปิดได้ ({ collection, id } หรือ { global }) หรือ null ส่วน cms.createPreviewToken({ collection, id }) ใช้สร้าง token เอง เช่น ปุ่ม "แชร์ลิงก์ตัวอย่าง"
ข้อควรรู้
- ให้ render rich text ฝั่ง client ด้วย (
renderRichTextจาก@easy-cms/richtextใช้ในเบราว์เซอร์ได้) เพราะเอกสารที่ส่งมามี rich text เป็น JSON - เมื่อใช้ adapter ของ Nuxt และ Next หน้าเว็บกับหน้า admin อยู่ origin เดียวกันและใช้ session เดียวกัน หน้าที่อ่าน ฉบับร่างให้ผู้ใช้ที่เข้าสู่ระบบ (อย่างที่ตัวอย่างทำ) จึงไม่ต้องใช้ token
- preview token เปิดได้เฉพาะเอกสารที่สร้างให้ หมดอายุใน 1 ชั่วโมง และถ้าถูกแก้ไขจะใช้ไม่ได้ ให้ถือว่า URL ของ preview เป็นลิงก์แชร์ชั่วคราว
- ดูตัวอย่างได้เฉพาะผู้ใช้ที่มีสิทธิ์แก้ไขเอกสารนั้น (หรือสิทธิ์สร้าง สำหรับเอกสารใหม่)
ขั้นต่อไป
- หลายภาษา (localization): ดูตัวอย่างแต่ละภาษา
- SEO: ดูตัวอย่างผลการค้นหาด้วย