เอาว่าเบื้องต้นคือไม่สามารถแยก CSR กับ SSR ได้ว่า มันทำงานต่างกันยังไง แต่พอจะมาทำ LINE LIFF แล้วก็เลยรู้ว่าระบบการแยกมันประมาณไหน
ซึ่งหลังจากติด Error กับ LIFF หนักมากๆ จนหาข้อมูลไปเรื่อยๆ เลยพบว่า LIFF เนี่ย มันทำงานได้ในฝั่ง CSR เท่านั้น ถ้ามันเรียกตอน SSR เมื่อไหร่ พังทันที!
ไปหาตัวอย่างดูตอนแรกๆ ก็ไม่รู้ ก็งงว่า ทำไม Svelte คนอื่นมันทำได้ แต่ของเราทำไม่ได้หว่า ดูไปดูมาอยู่หลายชั่วโมง ลองหลายรอบมาก จึงรู้ว่า เอ๊ะ มันแปลกๆ ทำไมมันเป็น Svelte เฉยๆ ไม่ใช่ SvelteKit นี่หว่า
โอเค หลังจากรู้ว่าต้องทำงานในฝั่ง CSR เท่านั้น SSR ห้าม ก็จะมีเส้นทางการทำอยู่ 2 เส้น คือ กำหนดให้เพจนี้ทำงานเป็น CSR ไปเลย หรือ ก็ใช้ SSR แต่ทำให้มันโหลดได้โดยไม่พัง
กำหนดหน้าเป็น CSR
ในการกำหนดหน้าเป็น CSR ก็สร้างหน้า +page.js แล้วใส่นี่เข้าไป
export const csr = true; export const ssr = false;
ง่ายๆ ก็ได้ละแค่นี้
ใช้ SSR แต่ทำให้ได้
ทีนี้มาท่ายาก อยากใช้เป็น SSR อยู่แต่ทำได้ด้วย ตอนแรกก็คิดว่าใช้ browser ของ SvelteKit ในการครอบ if ดีไหม ทำไปทำมามันไม่เวิร์ค ยากเกินไป เลยเปลี่ยนวิธีมาเป็น import @line/liff ตอน onMount แทน
<script> import { dev } from '$app/environment'; import { onMount } from 'svelte'; let promise = null; let profile = {}; let errorMessage = ''; onMount(async () => { const liff = await import('@line/liff'); promise = await liff.init({ liffId: 'this is line liff id' }); if (!liff.isInClient()) { errorMessage = 'หน้านี้ไม่ได้ถูกเปิดผ่านแอป LINE เลยทำให้ LIFF ไม่สามารถทำงานได้'; // ถ้ากำลัง dev ในเครื่อง แล้วเปิดในคอม ไม่ต้อง login if (!dev) { if (!liff.isLoggedIn()) { liff.login(); } } } profile = await liffGetProfile(); }); async function liffGetProfile() { const data = await liff.getProfile(); profile = { ...profile, pictureUrl: data.pictureUrl, userId: data.userId, statusMessage: data.statusMessage, displayName: data.displayName, email: liff.getDecodedIDToken().email }; } const closeWindow = () => { if (!liff.isInClient()) { window.alert(errorMessage); } else { liff.closeWindow(); } }; const sendMessage = async () => { if (!liff.isInClient()) { window.alert(errorMessage); } else { await liff.sendMessages([ { type: 'text', text: 'ขอบคุณที่จองคิว' } ]); } }; </script> <main> <h1>Liff Demo SSR</h1> {#if promise !== null} <p>LIFF init succeeded.</p> <div class="button"> <button on:click={sendMessage}>Send Message</button> <button on:click={closeWindow}>Close</button> </div> <hr /> <h3>User Info</h3> <ul> <li> <strong>User ID</strong> :<span>{profile.userId}</span> </li> <li> <strong>Display Name</strong> :<span>{profile.displayName}</span> </li> <li> <strong>Picture Url</strong> :<span><img src={profile.pictureUrl} width="100" /></span> </li> <li> <strong>E-mail</strong> :<span>{profile.email}</span> </li> <li> <strong>Status Message</strong> :<span>{profile.statusMessage}</span> </li> </ul> <h4 class="error">{errorMessage}</h4> <hr /> <h3>LIFF Info</h3> <ul> <li> <strong>LIFF Browser</strong> :<span>{liff.isInClient()}</span> </li> <li> <strong>Login Status</strong> :<span>{liff.isLoggedIn()}</span> </li> <li> <strong>Language</strong> :<span>{liff.getLanguage()}</span> </li> <li> <strong>OS</strong> :<span>{liff.getOS()}</span> </li> <li> <strong>LIFF Ver</strong> :<span>{liff.getVersion()}</span> </li> <li> <strong>LINE Ver</strong> :<span>{liff.getLineVersion()}</span> </li> </ul> <hr /> {/if} </main> <style> main { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } .error { color: red; } ul { list-style-type: none; text-align: left; margin: 0; padding: 0; } li { padding: 5px; border: 1px solid #dddddd; } li span { margin: 5px; } </style>
แล้วอยากบอกว่า เห็นสรุปมาง่ายๆ แบบนี้ ทำอยู่หลายเดือนเลย กว่าจะคิดออกและทำได้