<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nutchapon Makelai</title>
    <description>The latest articles on DEV Community by Nutchapon Makelai (@nnutnonn).</description>
    <link>https://dev.to/nnutnonn</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F941487%2Fe2211250-abef-482c-a164-b7fa8392fd1c.png</url>
      <title>DEV Community: Nutchapon Makelai</title>
      <link>https://dev.to/nnutnonn</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nnutnonn"/>
    <language>en</language>
    <item>
      <title>Sveltekit การทำงานกับ remote function [Part 2]</title>
      <dc:creator>Nutchapon Makelai</dc:creator>
      <pubDate>Fri, 10 Jul 2026 02:00:00 +0000</pubDate>
      <link>https://dev.to/nnutnonn/sveltekit-kaarthamngaankab-remote-function-part-2-4l2g</link>
      <guid>https://dev.to/nnutnonn/sveltekit-kaarthamngaankab-remote-function-part-2-4l2g</guid>
      <description>&lt;p&gt;สวัสดีครับเพื่อนๆ! 👋 กลับมาเจอกันอีกแล้วตามสัญญา! หลังจากบทความที่แล้วเราได้ทำความรู้จักกับพระเอกอย่าง query แบบเบสิกกันไปพอหอมปากหอมคอ วันนี้เราจะพามาอัปเลเวลความแอดวานซ์ขึ้นไปอีกขั้นครับ 🚀&lt;/p&gt;

&lt;p&gt;ใครที่เคยปวดหัวกับปัญหา N+1 ดึงข้อมูลซ้ำซ้อนจน Database ร้องขอชีวิต หรือกำลังอยากทำข้อมูลแบบ Real-time อัปเดตสดๆ ลื่นๆ... ปูเสื่อรอเลยครับ! เพราะวันนี้เราจะมาเจาะลึกทีเด็ดของ SvelteKit Remote function อีก 2 ท่า นั่นก็คือ query.batch() ฮีโร่ผู้มาช่วยมัดรวมรีเควสต์ และ query.live() สายสตรีมมิ่งข้อมูลแบบสดๆ! 🔥 จะเจ๋งและว้าวแค่ไหน ลุยกันเลยครับ! 👇&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;a href="https://svelte.dev/docs/kit/remote-functions#query.batch" rel="noopener noreferrer"&gt;📑 query.batch&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;ตัวนี้ทำงานคล้ายๆ รุ่นพี่ &lt;code&gt;query&lt;/code&gt; ปกติเลย แต่ &lt;code&gt;query.batch&lt;/code&gt; เกิดมาเพื่อเป็นฮีโร่แก้ปัญหาเวลาเราต้องเรียก &lt;code&gt;query&lt;/code&gt; ข้อมูลพร้อมกันหลายๆ ตัว (batches) ภายใต้ microtask เดียวกัน 🦸‍♂️ ซึ่งมันช่วยปราบปัญหา N+1 ได้แบบอยู่หมัด! แทนที่ข้อมูลแต่ละชิ้นจะต้องแยกกันยิง request ไปหา database มันกลับใช้วิธี รวมกลุ่ม (group) &lt;code&gt;query&lt;/code&gt; ทั้งหมดมัดรวมกัน แล้วส่งไปทีเดียวจบเลย! 📦&lt;/p&gt;

&lt;p&gt;พอมาถึงฝั่ง server (ไฟล์ &lt;code&gt;*.remote.js&lt;/code&gt;) สิ่งที่มันได้รับจะไม่ใช่ตัวแปรเดี่ยวๆ แต่จะมาเป็น &lt;code&gt;array&lt;/code&gt; ของตัวแปรทั้งหมดแทน 🍱 และทริคคือ ตอนเราส่งผลลัพธ์กลับไป เราจำเป็นต้องส่งกลับไปใน รูปแบบของฟังก์ชัน หน้าตาแบบนี้&lt;br&gt;
&lt;code&gt;(ค่าตัวแปรรับเข้า(input): Input, ค่าตำแหน่ง(index): number) =&amp;gt; Output&lt;/code&gt;&lt;br&gt;&lt;br&gt;
มึนๆใช่ม่ะ 😵‍💫 งั้นเรามาดูตัวอย่างกัน&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;valibot&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$app/server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$lib/server/database&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getWeather&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cityIds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;weather&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sql&lt;/span&gt;&lt;span class="s2"&gt;`
        SELECT * FROM weather
        WHERE city_id = ANY(&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;cityIds&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)
    `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//ตรงนี้จะส่ง cityIds ที่เป็น array ไปให้ database ค้นหาและส่งค่ากลับมา 🔍&lt;/span&gt;
         &lt;span class="c1"&gt;// ออกมาเป็น weather array ที่มีค่าข้อมูลของ id เมือง, ชื่อเมือง และสภาพอากาศ 🌤️&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lookup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;weather&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;city_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;]));&lt;/span&gt; &lt;span class="c1"&gt;//ตรงส่วนนี้จะทำการสร้าง Map ใหม่ 🗺️&lt;/span&gt;
        &lt;span class="c1"&gt;//โดยทำการ map array ให้เป็น array แบบ 2 มิติ [key,value]&lt;/span&gt;

        &lt;span class="c1"&gt;//หลังจากนั้นเราจะ return โดยให้สังเกตว่า cityId คือค่าที่เรา input เข้ามา แต่เป็น object เดี่ยวๆ&lt;/span&gt;
        &lt;span class="c1"&gt;//ไม่ใช่ array เหมือนที่รับเข้ามาผ่าน argument ด้านบนนะ ⚠️&lt;/span&gt;
        &lt;span class="c1"&gt;//และการ return ยังเป็น functions ที่จะใช้ Map.get(key) เพื่อดึงค่าข้อมูล weather ของเมืองนั้นๆ ออกไป 📤&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cityId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;lookup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cityId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;CityWeather&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./CityWeather.svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getWeather&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./weather.remote&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;cities&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;$props&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// รับค่าของ cities จาก props ที่ส่งเข้ามา (อาจจะมีมากกว่า 5 ข้อมูล) 🏙️&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;limit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;$state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// ตั้ง limit ว่าจะเอาข้อมูลกี่ตัว 📏&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Weather 🌤️&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- ทำการ slice เพื่อดึงข้อมูล 5 ตัวหน้าสุดออกมา --&amp;gt;&lt;/span&gt;
&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;#each&lt;/span&gt; &lt;span class="nx"&gt;cities&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h3&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- ส่ง city id เข้าไปยัง remote function แบบ 1-1 
             แต่ remote function จะเอาไปมัดรวมเป็น batch (array ของ city.id) ให้อัตโนมัติ ✨
             และส่งค่า weather ที่ได้รับกลับมาเข้าไปยัง component CityWeather ต่อไป 
        --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;CityWeather&lt;/span&gt; &lt;span class="na"&gt;getWeather&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="na"&gt;city.id&lt;/span&gt;&lt;span class="err"&gt;)}&lt;/span&gt; &lt;span class="na"&gt;weather=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&amp;gt;
{/each}

{#if cities.length &amp;gt; limit}
    &amp;lt;button onclick={() =&amp;gt; limit += 5}&amp;gt;
        Load more ➕
    &amp;lt;/button&amp;gt;
{/if}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;โดยขั้นตอนการทำงานแบบสรุปจากโค้ดด้านจะเป็นแบบนี้ครับ&lt;/p&gt;

&lt;p&gt;1️⃣ ฝั่ง Client: สั่งงานแบบเดี่ยวๆ แต่แอบรอเพื่อน (Microtask Grouping)&lt;br&gt;
จากโค้ดในหน้า &lt;code&gt;.svelte&lt;/code&gt; เรามีการใช้ &lt;code&gt;#each&lt;/code&gt; วนลูปสร้าง &lt;code&gt;&amp;lt;CityWeather&amp;gt;&lt;/code&gt; และเรียกใช้ &lt;code&gt;getWeather(city.id)&lt;/code&gt; ทีละเมือง&lt;/p&gt;

&lt;p&gt;ซึ่งแทนที่ฟังก์ชัน &lt;code&gt;getWeather&lt;/code&gt; จะวิ่งไปหา Server ทันทีทีละรอบ (ซึ่งถ้ามี 5 เมือง ก็จะยิง 5 Requests) ตัว SvelteKit จะทำการ "หน่วงเวลา" ไว้สั้นๆ ในระดับ Microtask เพื่อรอดูว่าในจังหวะนั้นมีการเรียก &lt;code&gt;getWeather&lt;/code&gt; ตัวอื่นๆ อีกไหม&lt;/p&gt;

&lt;p&gt;2️⃣ การมัดรวม (Batching) ก่อนส่ง&lt;br&gt;
เมื่อ SvelteKit เห็นว่ามีการเรียก &lt;code&gt;getWeather&lt;/code&gt; 5 ครั้งพร้อมๆ กัน มันจะทำการ มัดรวม (Batch) ค่า &lt;code&gt;city.id&lt;/code&gt; ทั้ง 5 ตัวนั้นเข้าด้วยกันให้กลายเป็น &lt;code&gt;Array&lt;/code&gt; ก้อนเดียว เช่น ['bkk', 'cnx', 'hdy', ...] แล้วส่ง Request ก้อนนี้ไปหา Server แค่ ครั้งเดียว! 📦&lt;/p&gt;

&lt;p&gt;3️⃣ ฝั่ง Server: รับก้อน Array ไปทำงานรอบเดียว&lt;br&gt;
ตัดภาพมาที่ไฟล์ &lt;code&gt;weather.remote.js&lt;/code&gt; บน Server&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getWeather&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cityIds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;สิ่งที่รับเข้ามา: พารามิเตอร์ cityIds จะไม่ได้รับค่าเป็น string เดี่ยวๆ แล้ว แต่จะได้รับเป็น Array ['bkk', 'cnx', 'hdy'] ตามที่ Client มัดรวมมาให้&lt;/li&gt;
&lt;li&gt;การ validation จะเป็นการตรวจสอบ &lt;strong&gt;แยกเดี่ยว&lt;/strong&gt; ของแต่ละข้อมูลภายใน &lt;code&gt;Array&lt;/code&gt; ที่ส่งเข้ามา&lt;/li&gt;
&lt;li&gt;การ Query (แบบประหยัดพลังงาน): เราเอา Array นี้ไปดึงข้อมูลจาก Database ในรอบเดียว (ผ่านคำสั่ง &lt;code&gt;ANY(${cityIds})&lt;/code&gt; หรือ &lt;code&gt;IN (...))&lt;/code&gt; ทำให้ Database ทำงานแค่ 1 ครั้ง ได้ผลลัพธ์สภาพอากาศของทุกเมืองกลับมาพร้อมกันเลย 🌩️&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;4️⃣ ฝั่ง Server: จัดเรียงข้อมูลให้ค้นหาง่าย (Mapping)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lookup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;weather&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;city_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;]));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;พอได้ข้อมูลมาจาก Database มันมักจะมาเป็น Array ธรรมดา เราจึงเอามาจัดลง Map (พจนานุกรมข้อมูล) โดยให้ &lt;code&gt;city_id&lt;/code&gt; เป็น Key และ &lt;code&gt;w&lt;/code&gt; (ข้อมูลสภาพอากาศ) เป็น Value เพื่อให้เดี๋ยวตอนดึงข้อมูลกลับไป จะได้ค้นหาได้ไวๆ ⚡ (ไม่ต้องไปนั่งลูปหาใหม่ทีละตัว)&lt;/p&gt;

&lt;p&gt;5️⃣ ฝั่ง Server: จุดพีค! การ Return ออกมาเป็น "ฟังก์ชัน"&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cityId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;lookup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cityId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;สังเกตว่าเรา ไม่ได้ return ข้อมูลกลับไปตรงๆ แต่เรา return ฟังก์ชัน กลับไปแทน! 🤯 เพราะ SvelteKit ฝั่ง Client ต้องการคนช่วย "แจกจ่าย" ข้อมูลให้ถูกคน มันจะเอาฟังก์ชันนี้ไปทำงานต่อ โดยจะโยน &lt;code&gt;city.id&lt;/code&gt; เดี่ยวๆ เข้ามาถามฟังก์ชันนี้ว่า "สภาพอากาศของเมืองนี้คืออะไร?" ฟังก์ชันนี้ก็จะไปหยิบค่าจากตู้ &lt;code&gt;lookup&lt;/code&gt; ที่เราสร้างไว้ในข้อ 4 ส่งคืนให้&lt;/p&gt;

&lt;p&gt;6️⃣ ฝั่ง Client: แจกจ่ายผลลัพธ์กลับสู่ Component&lt;/p&gt;

&lt;p&gt;เมื่อ SvelteKit ฝั่ง Client ได้รับฟังก์ชันแจกจ่ายของมาแล้ว มันก็จะทำหน้าที่แกะกล่อง Batch ออก แล้วส่งผลลัพธ์ (ข้อมูลสภาพอากาศ) กลับคืนไปให้ &lt;code&gt;&amp;lt;CityWeather&amp;gt;&lt;/code&gt; แต่ละตัวตามที่เคยขอไว้แบบ 1 ต่อ 1 อย่างแม่นยำเป๊ะ! 🎯&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;a href="https://svelte.dev/docs/kit/remote-functions#query.live" rel="noopener noreferrer"&gt;🟢query.live&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;ตัวนี้ก็อยู่แก๊งเดียวกับ &lt;code&gt;query&lt;/code&gt; แต่ทีเด็ดคือมันพกความสามารถในการดึงข้อมูลแบบ real-time จาก server มาด้วย!🔥 แต่จุดที่ต้องจำไว้คือ callback ของ &lt;code&gt;query.live&lt;/code&gt; จะเป็นฟังก์ชันสไตล์ generator function และของที่มันคายกลับมาให้เราจะอยู่ในรูปร่างหน้าตาของ &lt;code&gt;AsyncIterable&lt;/code&gt; แทน ลองดูตัวอย่างการใช้ &lt;code&gt;query.live&lt;/code&gt; ทำนาฬิกาแสดงเวลาทุกๆ 1 วินาทีกัน ⏰&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;getDateLive.remote.js&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$app/server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;live&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ในช่วงที่กำลังทำ server-side rendering อยู่ ตัว &lt;code&gt;await getTime()&lt;/code&gt; ที่โดนเรียกจากฝั่ง client จะคายค่าจาก &lt;code&gt;yield&lt;/code&gt; ออกมาให้เราก่อนเป็นออเดิร์ฟจานแรก 🍽️ แล้วมันก็จะพักเบรกการทำซ้ำทันที ซึ่งข้อมูลจานแรกนี่แหละ จะถูกหยิบมาใช้ต่อตอนทำ hydration นั่นเอง 💧&lt;/p&gt;

&lt;p&gt;พอข้ามมาฝั่ง client side เจ้าตัว &lt;code&gt;query.live&lt;/code&gt; จะทำตัวเป็นสายสืบที่เชื่อมต่ออยู่ตลอดเวลาตราบใดที่มันยังเกาะติดอยู่กับ component 🕵️‍♀️ และถ้ามีหลาย instance เกิดขึ้น พวกมันก็จะใจดีแชร์ท่อเชื่อมต่อเส้นเดียวกันทั้งหมด 🤝 แต่เมื่อไหร่งานเลี้ยงเลิกรา ไม่มีใครเรียกใช้มันแล้ว การเชื่อมต่อก็จะถูกตัดฉับ! การ stream หยุดลง และระบบทำซ้ำก็จะหยุดตามไปด้วย 💤&lt;/p&gt;

&lt;p&gt;นอกจากนี้ เจ้า live query ที่ถูกส่งข้ามมาฝั่ง client ยังใจดีแถม property และ method พิเศษมาให้ใช้เพิ่มอีก 2 ตัวนะคือ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;connected&lt;/code&gt;  🔌&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;reconnect()&lt;/code&gt;  🔄&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;src/routes/time/+page.svelte&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getTime&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./time.remote.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;connected: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connected&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reconnect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Reconnect 🔄&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ถ้าวันดีคืนดีเกิดเหตุไม่คาดฝัน เน็ตหลุด หรือเกิด error จนคุยกับ remote function ไม่รู้เรื่อง 💔 ค่า &lt;code&gt;connected&lt;/code&gt; จะเปลี่ยนเป็น &lt;code&gt;false&lt;/code&gt; ทันที แต่ไม่ต้องตกใจไป! Sveltekit จะพยายามฮึดสู้กู้การเชื่อมต่อให้เราอัตโนมัติ (ใช้วิธีเช็คซ้ำแบบ exponential backoff คือยิ่งต่อไม่ติด ก็จะยิ่งทิ้งช่วงรอนานขึ้นเรื่อยๆ) ซึ่งในจังหวะนั้น ค่า &lt;code&gt;window.navigator.onLine&lt;/code&gt; ของเบราว์เซอร์ก็จะกลายเป็น false ไปด้วยนะ 📉&lt;/p&gt;

&lt;p&gt;แต่ถ้า &lt;code&gt;window.navigator.onLine&lt;/code&gt; กลับมาเป็น &lt;code&gt;true&lt;/code&gt; และระบบเชื่อมต่อกลับไปหา remote function บน server ได้สำเร็จ ค่า &lt;code&gt;connected&lt;/code&gt; ก็จะกลับมายิ้มแฉ่งเป็น &lt;code&gt;true&lt;/code&gt; อีกครั้ง! 🌈&lt;/p&gt;

&lt;p&gt;และที่สำคัญ สำหรับ &lt;code&gt;query.live&lt;/code&gt; จะไม่มี method &lt;code&gt;refresh()&lt;/code&gt; ให้เรียกนะ ❌ เพราะตัวมันเองสุดยอดอยู่แล้ว สามารถอัปเดตข้อมูลตัวเองได้ตลอดเวลาแบบ self-updating เลย 😎&lt;/p&gt;

&lt;p&gt;แต่ถ้าใครสายฮาร์ดคอร์ 🎸 อยากล้วงลึกเข้าไปจัดการข้อมูลในระดับ stream เอง แทนที่จะนั่งรอข้อมูล reactive แบบง่ายๆ ผ่าน &lt;code&gt;current&lt;/code&gt; คุณก็สามารถสร้าง &lt;code&gt;async function&lt;/code&gt; มารับช่วงต่อ แล้วเปิดใช้ &lt;code&gt;for...await&lt;/code&gt; กวาดข้อมูลข้างในมาเล่นได้เลย! 🌪️ เพราะว่าเนื้อแท้แล้ว ของที่ remote function แบบ live โยนกลับมาให้ ก็ยังมีหน้าตาเป็น &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of" rel="noopener noreferrer"&gt;&lt;code&gt;async-iterable&lt;/code&gt;&lt;/a&gt; อยู่ดีนั่นแหละ&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;src/routes/time/+page.svelte&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;async function logTimes() &lt;span class="si"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;await &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;someCondition&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="si"&gt;}&lt;/span&gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ซึ่งผู้ใช้งานที่ดึง live query ตัวเดียวกันมาเล่นในช่วงเวลาเดียวกัน (ไม่ว่าจะใช้ท่า &lt;code&gt;await&lt;/code&gt;, &lt;code&gt;current&lt;/code&gt; หรือเปิดลูป &lt;code&gt;for...await&lt;/code&gt;) ระบบจะจับยัดให้ใช้ท่อการเชื่อมต่อเส้นเดียวกันทั้งหมดเลยทันที&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ข้อควรระวังฝั่ง Client&lt;/strong&gt;: ⚠️ สำหรับท่า &lt;code&gt;for...await&lt;/code&gt; นั้น ข้อมูลชิ้นแรกสุดที่จะวิ่งเข้ามาหาเรา จะเป็นข้อมูลอัปเดตตัว "ล่าสุด" ที่โดนดึงมาจาก instance อื่นๆ (most-recently-received value) 🆕 และถ้าสมมติว่าฝั่ง server สาดข้อมูลมาเร็วจัดจน Client ย่อยไม่ทัน ระบบจะ เก็บไว้เฉพาะค่าล่าสุดที่ค้างอยู่เท่านั้น 📌 (เพราะคอนเซปต์ของ Live Stream ไม่ใช่ Event Log นะครับ มันเลยไม่ได้เก็บประวัติย้อนหลังทั้งหมดไว้ให้)&lt;/p&gt;

&lt;p&gt;ส่วนการทำงานบนฝั่ง Server: 🖥️ คำสั่ง &lt;code&gt;for...await&lt;/code&gt; บนเซิร์ฟเวอร์จะทำงานแบบแชร์รอบกัน (Shared Iteration) ร่วมกันในแต่ละ Request ส่งผลให้แม้ว่าจะมีผู้ใช้หลายคนแห่มาเรียกใช้พร้อมๆ กันใน Request เดียวกัน มันก็ฉลาดพอที่จะไม่สั่งให้ตัว Generator ต้องวิ่งเต้นรันซ้ำซ้อนให้เปลืองแรง 🧠&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🚨🚨 สำคัญ!! ห้ามไปเผลอทำแคช (Cache) ผลลัพธ์ของ Live Query ใน Service Worker เด็ดขาด! เพราะมันจะทำให้ข้อมูลที่ถูกก๊อปปี้ไป ดันนั่งสตรีมตัวเองต่อไปเรื่อยๆ อย่างไม่รู้จักเหน็ดเหนื่อย แม้ว่าเราจะกดปิดหน้าเว็บทิ้งไปแล้วก็ตาม 😱 และอย่าลืมเช็คให้ชัวร์ด้วยว่า ระบบดักแคชของคุณได้เตะเอา Responses ที่แปะป้าย &lt;code&gt;Cache-Control&lt;/code&gt; ว่า &lt;code&gt;no-store&lt;/code&gt; ออกไปจากการทำแคชเรียบร้อยแล้ว 🧹&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;เป็นยังไงกันบ้างครับเพื่อนๆ กับความทรงพลังของ query.batch() และ query.live() 🤯 บอกเลยว่า SvelteKit รอบนี้เขาทำการบ้านมาดีมากจริงๆ ช่วยให้ชีวิต Dev อย่างเราง่ายขึ้นเยอะ โค้ดคลีนขึ้น แถมประหยัดทรัพยากรฝั่ง Server ไปได้อีกเพียบ! 🎉&lt;/p&gt;

&lt;p&gt;แต่เดี๋ยวก่อน... มหากาพย์ Remote function ของเรายังไม่จบลงแค่นี้นะครับ! 🎬 ที่ผ่านมาเราเน้นแต่เรื่องการ "ดึงข้อมูล" มาแสดงผลกันไปแล้ว แล้วถ้าเราอยากจะ "ส่งข้อมูล" หรือบันทึกอะไรบางอย่างกลับไปที่ Server ล่ะ ต้องทำยังไง? 🤔&lt;/p&gt;

&lt;p&gt;ในบทความหน้า เราจะเปลี่ยนฟีลจากตระกูล query ไปทำความรู้จักกับ Remote function อีกประเภทหนึ่งที่เกิดมาเพื่อจัดการเรื่องการส่งข้อมูล (Mutation) โดยเฉพาะ! นั่นก็คือ form 📝 ครับผม! มันจะมาช่วยลบภาพความยุ่งยากของการจัดการฟอร์มแบบเดิมๆ ออกไปได้ยังไง เตรียมตัวรอติดตามกันในบทความถัดไปได้เลยครับ! แล้วเจอกัน 😉✨&lt;/p&gt;

</description>
      <category>svelte</category>
      <category>sveltekit</category>
      <category>webdev</category>
      <category>thai</category>
    </item>
    <item>
      <title>Sveltekit การทำงานกับ remote function [Part 1]</title>
      <dc:creator>Nutchapon Makelai</dc:creator>
      <pubDate>Fri, 03 Jul 2026 06:31:24 +0000</pubDate>
      <link>https://dev.to/nnutnonn/sveltekit-kaarthamngaankab-remote-function-part-1-4hg4</link>
      <guid>https://dev.to/nnutnonn/sveltekit-kaarthamngaankab-remote-function-part-1-4hg4</guid>
      <description>&lt;p&gt;สวัสดีครับเพื่อนๆ! 👋 วันนี้จะมาเล่าเรื่องน่าตื่นเต้นให้ฟังนะเพื่อนๆ สำหรับใครที่เป็นสาย SvelteKit เตรียมตัวอัปเดตความรู้ใหม่กันได้เลย เพราะตอนนี้เขามีของเล่นใหม่ที่กำลังอยู่ในช่วงทดลองใช้งาน แต่บอกเลยว่าว้าวมาก! เราไปดูกันดีกว่าว่ามันคืออะไร...&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://svelte.dev/docs/kit/remote-functions" rel="noopener noreferrer"&gt;📡 Remote function คืออะไร&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;เป็น function ตัวใหม่ ✨ (ที่คาดว่าจะเป็น new way to implement สำหรับ Sveltekit 3.0) เอาไว้ใช้สื่อสารพูดคุยกันระหว่างฝั่ง client และ server ของ Sveltekit นั่นเอง 💬&lt;/p&gt;

&lt;p&gt;ความเจ๋งคือเราสามารถเรียกใช้มันจากมุมไหนของ Sveltekit ก็ได้ 🌍 ไม่จำเป็นต้องจำกัดแค่ฝั่ง server หรือ client แต่จุดสำคัญคือ &lt;strong&gt;การทำงานของมันจะเกิดขึ้นที่ฝั่ง server เสมอ&lt;/strong&gt; 👍 นั่นหมายความว่ามันสามารถทะลุทะลวงไปดึงข้อมูลหรือโมดูลที่เป็น server-only ได้สบายๆ เช่น ตัวแปร environment ที่เราประกาศไว้ หรือพวกฐานข้อมูลต่างๆ ก็ดึงมาได้ชิลๆ เลย 😎&lt;/p&gt;

&lt;p&gt;เวลาจะใช้งาน เราจะต้องใช้ท่าการ &lt;code&gt;await&lt;/code&gt; แบบใหม่ของ Sveltekit ⏳ ที่ช่วยให้คุณโหลดหรือดึงข้อมูลแบบ promise มาใช้ใน component ของคุณได้ทันที 🚀&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;หมายเหตุ:&lt;/strong&gt; ตอนนี้ทั้ง &lt;code&gt;await&lt;/code&gt; และ remote function ยังอยู่ในช่วงทดลองใช้งาน 🧪 (experimental) นั่นแปลว่า syntax บางอย่างอาจจะมีการปรับเปลี่ยนหรือบินหายไปบ้างในอนาคต 🥲 แต่แกนหลัก (core functional) ของมันก็จะยังทำงานได้ตามที่เราคาดหวังแน่นอน&lt;/p&gt;

&lt;p&gt;ถ้าใครคันไม้คันมืออยากลองของใหม่ตอนนี้ สามารถไปเปิดโหมด experimental ได้ที่ไฟล์ &lt;code&gt;svelte.config.js(.ts)&lt;/code&gt; ตามโค้ดด้านล่างนี้เลย 👇&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;svelte.config.js(.ts)&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/** @type {import('@sveltejs/kit').Config} */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;kit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;experimental&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;remoteFunctions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;compilerOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;experimental&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;async&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  &lt;a href="https://svelte.dev/docs/kit/remote-functions#Overview" rel="noopener noreferrer"&gt;🏃‍♂️ Let get started!!&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;เราสามารถเริ่มใช้ remote function ได้ง่ายๆ ผ่านการสร้างไฟล์นามสกุล &lt;code&gt;.remote.js&lt;/code&gt; หรือ &lt;code&gt;.remote.ts&lt;/code&gt;  📝 ซึ่งตอนนี้มี function ให้เราหยิบมาเล่นทั้งหมด 4 ตัวด้วยกันคือ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;query (ที่เราจะมาพูดถึงกันในบทความนี้)&lt;/li&gt;
&lt;li&gt;form&lt;/li&gt;
&lt;li&gt;command&lt;/li&gt;
&lt;li&gt;prerender&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;หลักการทำงานเบื้องหลังคือ เวลาที่เรา import ตัว remote function ไปใช้ในฝั่ง client มันจะถูกแอบแปลงร่างเป็นโค้ดที่หุ้มด้วย &lt;code&gt;fetch&lt;/code&gt; ในช่วง build time 🏗️ นั่นหมายความว่าระบบจะใจดีสร้างเส้น HTTP endpoint ให้เราแบบอัตโนมัติ ✨ ด้วยเหตุนี้เราเลยเอาไฟล์ &lt;code&gt;.remote.js&lt;/code&gt; หรือ &lt;code&gt;.remote.ts&lt;/code&gt; ไปแปะไว้ตรงไหนก็ได้ภายใต้โฟลเดอร์ &lt;code&gt;/src&lt;/code&gt;  &lt;/p&gt;

&lt;p&gt;🚨 ยกเว้น! ห้ามเอาไปวางในโฟลเดอร์ &lt;code&gt;/src/lib/server&lt;/code&gt; เด็ดขาดนะ เพราะทำไมนะหรอ เพราะมันเป็น folder ที่ถูกล๊อคชื่อไว้เพื่อใช้เป็น &lt;a href="https://svelte.dev/docs/kit/server-only-modules" rel="noopener noreferrer"&gt;server-only module&lt;/a&gt; ยังไงละ❗&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;a href="https://svelte.dev/docs/kit/remote-functions#query" rel="noopener noreferrer"&gt;🔍 query &lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;คำสั่งนี้เอาไว้สำหรับค้นหาข้อมูลแล้วดึงมาแสดงผลชิลๆ 🕵️‍♂️ อารมณ์เหมือนเวลาเราเรียก HTTP Method &lt;code&gt;GET&lt;/code&gt; นั่นแหละ&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ทริคเล็กๆ: ถ้าข้อมูลของเราเป็นแบบคงที่ (static data) ไม่ค่อยเปลี่ยน แนะนำให้เลี้ยวไปใช้คำสั่ง &lt;code&gt;prerender&lt;/code&gt; จะเวิร์คกว่า เพราะตัว &lt;code&gt;query&lt;/code&gt; จะไม่สามารถทำงานได้ถ้าหน้า page นั้นถูกตั้งค่าเป็น &lt;a href="https://svelte.dev/docs/kit/page-options#prerender" rel="noopener noreferrer"&gt;prerender&lt;/a&gt; ทั้งหมด&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;มาดูตัวอย่างการสร้าง remote function ด้วยคำสั่ง &lt;code&gt;query&lt;/code&gt; ภายใต้ไฟล์ &lt;code&gt;src/routes/blog/data.remote.js&lt;/code&gt; กันครับ&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;src/routes/blog/data.remote.js&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$app/server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$lib/server/database&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getPosts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sql&lt;/span&gt;&lt;span class="s2"&gt;`
        SELECT title, slug
        FROM post
        ORDER BY published_at
        DESC
    `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;📌 หมายเหตุ: ในตัวอย่างต่อๆ ไป จะเห็นว่ามีการ import พวก &lt;code&gt;$lib/server/database&lt;/code&gt; และ &lt;code&gt;$lib/server/auth&lt;/code&gt; เข้ามาด้วย อันนี้เป็นแค่โมดูลจำลองเพื่อให้เห็นภาพการทำงานเฉยๆ นะ ของจริงคุณสามารถเชื่อมต่อไปยัง database หรือ service ตัวไหนก็ได้ตามใจชอบเลย 🔌 ส่วน &lt;code&gt;db.sql&lt;/code&gt; ก็เป็นแค่ฟังก์ชันสมมติให้ดูว่าเรากำลังคุยกับ database อยู่เท่านั้นจ้า&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;ซึ่งตัวข้อมูลที่จะส่งกลับมาผ่านฟังก์ชัน &lt;code&gt;getPosts&lt;/code&gt; จะทำงานอยู่ในรูปแบบ &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise" rel="noopener noreferrer"&gt;&lt;code&gt;Promise&lt;/code&gt;&lt;/a&gt; ⏳ ซึ่งเดี๋ยวมันจะถูกแปลงร่างออกมาเป็นข้อมูล posts ให้เราใช้งานได้นั่นเอง 📄&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;src/routes/blog/+page.svelte&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getPosts&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./data.remote&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Recent posts&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
    &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;#each&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getPosts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;slug&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/blog/{slug}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
    &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;/each&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;สังเกตไหมว่าเวลาเราหยิบ remote function ประเภท &lt;code&gt;query&lt;/code&gt; มาใช้ในฝั่ง client side เราจะต้องแปะ &lt;code&gt;await&lt;/code&gt; ไว้เสมอ ซึ่งถ้าแจ็คพอตแตก ฟังก์ชัน &lt;code&gt;query&lt;/code&gt; เกิด error ขึ้นมา 💥 ระบบก็จะเด้งพาเราไปยังหน้า &lt;code&gt;+error.svelte&lt;/code&gt; หรือแสดงผลตาม  &lt;code&gt;&amp;lt;svelte:boundary&amp;gt;&lt;/code&gt; ตัวที่อยู่ใกล้ที่สุดให้เอง 🛡️&lt;/p&gt;

&lt;p&gt;แต่เดี๋ยวก่อน! ฟังก์ชัน &lt;code&gt;query&lt;/code&gt; ที่ถูก import เข้ามาในฝั่ง client ยังมี properties ลับๆ ให้เราเรียกใช้เพื่อจัดการเรื่องเวลา (timing) ได้เนียนขึ้น แถมไม่ต้องพึ่ง &lt;code&gt;await&lt;/code&gt; ตลอดด้วยนะ โดยมี properties ให้ใช้คือ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;loading&lt;/code&gt;   ⏳&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;error&lt;/code&gt;   ❌&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;current&lt;/code&gt;   ✅&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;src/routes/blog/+page.svelte&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getPosts&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./data.remote&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getPosts&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Recent posts&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;#if&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;จะ render ตอนเกิด error ขึ้น 🚨&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;:else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;จะ render ระหว่างที่ query function นั้นทำการ fetch ข้อมูล 🔄&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
// จะ render เมื่อ query function ทำการ fetch เรียบร้อย และสำเร็จ ✨
    &lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;#each&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;slug&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/blog/{slug}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;/each&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;/if&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;📖 ปล. แต่ในหัวข้อถัดๆ ไปของบทความนี้ เราจะเน้นใช้งานรูปแบบการเรียกผ่าน &lt;code&gt;await&lt;/code&gt; เป็นหลักเพื่อความกระชับนะ&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  &lt;a href="https://svelte.dev/docs/kit/remote-functions#query-Query-arguments" rel="noopener noreferrer"&gt;🔣Query arguments&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;แน่นอนว่าฟังก์ชัน &lt;code&gt;query&lt;/code&gt; ยอมให้เราโยนตัวแปร หรือ arguments เข้าไปได้ด้วย 📨 เช่น ถ้าเราอยากจะหยิบข้อมูล &lt;code&gt;slug&lt;/code&gt; จาก URL parameters แล้วส่งเข้าไปในฟังก์ชัน &lt;code&gt;query&lt;/code&gt; ก็ทำได้สบายๆ แบบนี้เลย 👇&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;src/routes/blog/[slug]/+page.svelte&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getPost&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../data.remote&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;$props&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;//ดึงข้อมูล parameters จาก url 🔗&lt;/span&gt;

        &lt;span class="c1"&gt;//นำ parameters ที่มี key ชื่อว่า slug ส่งเข้า remote function 📨&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;$derived&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;  
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;@html&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ข้อควรระวังคือ เวลาเราโยนตัวแปรเข้าหา remote function เราต้องตรวจสอบ (validate) ความถูกต้องของข้อมูลด้วยนะ ว่าเป็นประเภทข้อมูลที่ถูกต้องไหม ✅ ซึ่งตรงนี้เราจำเป็นต้องพึ่งพวก library ตรวจข้อมูลที่รองรับ &lt;a href="https://standardschema.dev/" rel="noopener noreferrer"&gt;Standard Schema&lt;/a&gt; อย่างเช่น &lt;a href="https://valibot.dev/" rel="noopener noreferrer"&gt;Valibot&lt;/a&gt; หรือ &lt;a href="https://zod.dev/" rel="noopener noreferrer"&gt;Zod&lt;/a&gt; มาช่วยเป็นยามเฝ้าประตูให้ 👮‍♂️&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;src/routes/blog/data.remote.js&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;valibot&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@sveltejs/kit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$app/server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$lib/server/database&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getPosts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
                          &lt;span class="c1"&gt;// vvvvvvv ใส่ schema ตรงนี้ก่อนเข้า function 🛡️&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getPost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sql&lt;/span&gt;&lt;span class="s2"&gt;`
        SELECT * FROM post
        WHERE slug = &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
    `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Not found&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;และไม่ต้องห่วงเรื่องข้อมูลซับซ้อน เพราะไม่ว่าจะเป็นตัวแปรที่รับเข้ามา หรือข้อมูลที่ส่งกลับไป ทั้งหมดจะถูกแปลงผ่านกลไกที่เรียกว่า &lt;code&gt;devalue&lt;/code&gt; 🔄 ซึ่งเจ๋งตรงที่มันรองรับประเภทข้อมูลอย่าง &lt;code&gt;Date&lt;/code&gt; และ &lt;code&gt;Map&lt;/code&gt; (หรือประเภทข้อมูลอื่นๆที่เราสร้างเองผ่าน transport hook ด้วย) ได้ด้วย (รวมถึงประเภทข้อมูลแปลกๆ ที่เราสร้างเองผ่าน transport hook ด้วยนะ) ทำให้มันทรงพลังและยืดหยุ่นกว่าการใช้ &lt;code&gt;JSON.stringify&lt;/code&gt; แบบปกติเยอะเลย 💪&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🧠 เกร็ดความรู้: สำหรับคำสั่ง &lt;code&gt;query&lt;/code&gt; หรือ &lt;code&gt;prerender&lt;/code&gt; ถ้าเราโยนตัวแปรแบบ object, maps หรือ sets เข้าไป แล้วข้อมูลข้างในหน้าตาเหมือนกันเป๊ะ แค่สลับที่กัน ระบบจะมองว่าเป็น cache key ตัวเดียวกันเลยนะ! เช่น &lt;code&gt;getPosts({ limit: 10, offset: 10 })&lt;/code&gt; กับ &lt;code&gt;getPosts({ offset: 10, limit: 10 })&lt;/code&gt; ถือว่าเป็นตัวเดียวกัน 👯‍♀️ แต่ถ้าโปรเจกต์ของคุณมองว่า "ลำดับ" การเรียงมีความสำคัญมาก ไม่อยากให้มันมองเป็น cache key เดียวกัน แนะนำให้เปลี่ยนไปส่งข้อมูลเป็น &lt;code&gt;array&lt;/code&gt; แทนนะ &lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  &lt;a href="https://svelte.dev/docs/kit/remote-functions#query-Deduplication" rel="noopener noreferrer"&gt;👯Deduplication&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;นี่คือฟีเจอร์ "ป้องกันการขอข้อมูลซ้ำซ้อน" 🚫 ปกติแล้วพอเราเรียกใช้ฟังก์ชัน &lt;code&gt;query&lt;/code&gt; ตัว Sveltekit จะจัดการแอบจำตัวแปรที่ส่งเข้าไป แล้วสร้างเก็บเป็น cache key 🗝️ ไว้ ซึ่งในฝั่ง server เจ้า cache key ตัวนี้จะถูกเอาไปใช้สร้างแคชแบบ request-scoped สิ่งนี้ทำให้การเรียกขอข้อมูลซ้ำๆ ผ่าน &lt;code&gt;query&lt;/code&gt; ด้วยตัวแปรเดิม ระบบจะประมวลผลให้ แค่เพียงครั้งเดียวเท่านั้น! ⚡ ทำให้ได้ผลลัพธ์ไวขึ้นเยอะ แถมยังช่วยลดภาระไม่ให้รัว request ไปถล่มฝั่ง database อีกต่างหาก 😌&lt;/p&gt;

&lt;p&gt;เราสามารถหยิบ &lt;code&gt;await&lt;/code&gt; ไปวางไว้ตรงไหนก็ได้ตามสะดวก ไม่ว่าจะเป็นในระดับ components, event handlers, &lt;a href="https://svelte.dev/docs/kit/load#Universal-vs-server" rel="noopener noreferrer"&gt;universal load function&lt;/a&gt; หรือแม้แต่ async callback 🎯 Sveltekit จะช่วยจัดการรวบตึงการทำซ้ำ (deduped) ให้ทันที ถ้าจับได้ว่ามีการเรียกใช้ &lt;code&gt;query&lt;/code&gt; ด้วยตัวแปรเดิมใน cache key มาดูตัวอย่างกัน&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;src/routes/deduped/+page.svelte&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getData&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./data.remote.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// ใช้ await ในระดับ component template -- ทำการสร้าง cache key 🗝️&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- แต่ในส่วนนี้ถูกเรียกใช้งานอีกครั้ง ซึ่ง sveltekit จะทำการ dedupes 
ข้อมูลกับส่วน component template ด้านบนให้เอง ซึ่งจะไม่ทำให้เกิด request เพิ่มเติมวิ่งไปหา database 🛡️ --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getData&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    click me!
&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ตัว cache key นี้จะถูกส่งต่อและแชร์ให้กันตลอดตราบใดที่ &lt;code&gt;query&lt;/code&gt; ยังมีคนเรียกใช้งานอยู่ เช่น ตอนที่ component กำลัง render, ตอนกำลังใช้ &lt;code&gt;await&lt;/code&gt; หรือโดนอ้างอิงจากที่อื่น แต่พอหมดคนใช้งานแล้ว ข้อมูลแคชก็จะถูกลบหรือ release ทิ้งไปสวยๆ 💨 เช่น ตอนที่ผู้ใช้กด refresh หน้าเว็บ เป็นต้น&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;a href="https://svelte.dev/docs/kit/remote-functions#query-Refreshing-queries" rel="noopener noreferrer"&gt;♻️ Refreshing queries&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;ในจังหวะที่เราอยากจะขออัปเดตดึงข้อมูลให้เป็นของใหม่จริงๆ ฟังก์ชัน &lt;code&gt;query&lt;/code&gt; ก็เตรียม method มาให้เราไปดูดข้อมูลมาใหม่ (re-fetched) ได้ด้วยนะ 🔄 โดยเรียกใช้ method ที่ชื่อว่า &lt;code&gt;refresh&lt;/code&gt; เจ้านี่จะวิ่งหน้าตั้งไป fetch เพื่อหอบเอาข้อมูลใหม่ล่าสุดจาก server กลับมาเสิร์ฟให้เราทันที 🏃‍♂️💨&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;src/routes/blog/+page.svelte&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getPosts&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;refresh&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    Check for new posts 🔄
&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡 อย่างที่รู้กันว่า &lt;code&gt;query&lt;/code&gt; มันถูกจำ (cache) ไว้ตอนเราอยู่หน้าเพจนั้นๆ แปลว่า &lt;code&gt;getPosts() === getPosts()&lt;/code&gt; เป๊ะ! ดังนั้นคุณไม่ต้องเหนื่อยไปประกาศตัวแปรซ้ำๆ อย่าง &lt;code&gt;const posts = getPosts()&lt;/code&gt; เป็นทอดๆ เพียงเพื่อหวังให้ &lt;code&gt;query&lt;/code&gt; มันอัปเดตหรอกนะ สบายใจได้เลย 💓&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;เป็นยังไงกันบ้างครับเพื่อนๆ กับการใช้งาน query เบื้องต้น ไม่ยากอย่างที่คิดเลยใช่ไหมล่ะ? 😁 แต่อย่างที่บอกไปตอนแรกว่าฟังก์ชันมันไม่ได้มีแค่นี้นะ! สำหรับบทความนี้คงต้องขอพักไว้ตรงนี้ก่อน แล้วเดี๋ยวในบทความหน้า... เราจะไปคุยกันต่อแบบเจาะลึกในเรื่องของ query.batch() และ query.live() 🚀 รับรองว่ามีทีเด็ดรออยู่อีกเพียบ เตรียมตัวรอติดตามกันได้เลยครับ! 😉✨&lt;/p&gt;

</description>
      <category>svelte</category>
      <category>sveltekit</category>
      <category>webdev</category>
      <category>thai</category>
    </item>
    <item>
      <title>Stop flickering theme after page refresh in Sveltekit and Daisy UI</title>
      <dc:creator>Nutchapon Makelai</dc:creator>
      <pubDate>Tue, 14 Nov 2023 09:39:19 +0000</pubDate>
      <link>https://dev.to/nnutnonn/stop-flickering-theme-after-page-refresh-in-sveltekit-and-daisy-ui-2i74</link>
      <guid>https://dev.to/nnutnonn/stop-flickering-theme-after-page-refresh-in-sveltekit-and-daisy-ui-2i74</guid>
      <description>&lt;p&gt;Hi, Sveltian today I would like to share you how to stop theme flickering after we refreshing a page while we using &lt;a href="https://daisyui.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;Daisy UI&lt;/strong&gt;&lt;/a&gt; with &lt;a href="https://kit.svelte.dev/" rel="noopener noreferrer"&gt;&lt;strong&gt;Sveltekit&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  New in Daisy UI 4.0
&lt;/h2&gt;

&lt;p&gt;Now with Daisy UI 4.0 has been release with new component call &lt;a href="https://daisyui.com/components/theme-controller/" rel="noopener noreferrer"&gt;&lt;strong&gt;Theme Controller&lt;/strong&gt;&lt;/a&gt; it bring us to a more easier way to change between two theme in Daisy UI , for more info about what change and what new  in Daisy UI 4.0 let check this &lt;a href="https://daisyui.com/docs/changelog/#400-2023-11-12" rel="noopener noreferrer"&gt;&lt;strong&gt;link&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Let see what Theme Controller can do
&lt;/h2&gt;

&lt;p&gt;Now I expected you has been installing a new Sveltekit project (with a Skeleton Project option selected) &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvpj0ym1fz59dgrzyk210.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvpj0ym1fz59dgrzyk210.png" alt=" " width="797" height="107"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tailwind CSS and Daisy UI , then we will starting our code&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;checking you tailwind.config.js , need to have at least 2 of any themes (&lt;a href="https://daisyui.com/docs/themes/" rel="noopener noreferrer"&gt;how to setup themes&lt;/a&gt;) &lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;I have set 2 customize theme name '&lt;strong&gt;light&lt;/strong&gt;' and '&lt;strong&gt;dark&lt;/strong&gt;'&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsowec8uu77i8zr65je31.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsowec8uu77i8zr65je31.png" alt="theme name '**light**' and '**dark**'" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;adding attribute &lt;code&gt;data-theme&lt;/code&gt; on &lt;code&gt;html&lt;/code&gt; tag in &lt;code&gt;src/app.html&lt;/code&gt; page&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;for me will set it as '&lt;strong&gt;light&lt;/strong&gt;' theme by default while page is loaded&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9orby2z0i0hayriy8xlv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9orby2z0i0hayriy8xlv.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;build svelte component name 'ModeSwitcher' (this name is up to your decide) and in that svelte component put below code into it and using this component on &lt;code&gt;+layout.svelte&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;I has using  &lt;a href="https://daisyui.com/components/theme-controller/#theme-controller-using-a-swap" rel="noopener noreferrer"&gt;Theme Controller using a swap component&lt;/a&gt; from DaisyUI and set it value to 'dark' as it is my dark mode theme name&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;label class="swap swap-rotate"&amp;gt;
    &amp;lt;!-- this hidden checkbox controls the state --&amp;gt;
    &amp;lt;input
        type="checkbox"
        class="theme-controller"
        value="dark"
    /&amp;gt;

    &amp;lt;!-- sun icon --&amp;gt;
    &amp;lt;svg class="swap-on fill-current w-10 h-10" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&amp;gt;
        &amp;lt;path d="M5.64,17l-.71.71a1,1,0,0,0,0,1.41,1,1,0,0,0,1.41,0l.71-.71A1,1,0,0,0,5.64,17ZM5,12a1,1,0,0,0-1-1H3a1,1,0,0,0,0,2H4A1,1,0,0,0,5,12Zm7-7a1,1,0,0,0,1-1V3a1,1,0,0,0-2,0V4A1,1,0,0,0,12,5ZM5.64,7.05a1,1,0,0,0,.7.29,1,1,0,0,0,.71-.29,1,1,0,0,0,0-1.41l-.71-.71A1,1,0,0,0,4.93,6.34Zm12,.29a1,1,0,0,0,.7-.29l.71-.71a1,1,0,1,0-1.41-1.41L17,5.64a1,1,0,0,0,0,1.41A1,1,0,0,0,17.66,7.34ZM21,11H20a1,1,0,0,0,0,2h1a1,1,0,0,0,0-2Zm-9,8a1,1,0,0,0-1,1v1a1,1,0,0,0,2,0V20A1,1,0,0,0,12,19ZM18.36,17A1,1,0,0,0,17,18.36l.71.71a1,1,0,0,0,1.41,0,1,1,0,0,0,0-1.41ZM12,6.5A5.5,5.5,0,1,0,17.5,12,5.51,5.51,0,0,0,12,6.5Zm0,9A3.5,3.5,0,1,1,15.5,12,3.5,3.5,0,0,1,12,15.5Z" /&amp;gt;
    &amp;lt;/svg&amp;gt;

    &amp;lt;!-- moon icon --&amp;gt;
    &amp;lt;svg class="swap-off fill-current w-10 h-10" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&amp;gt;
        &amp;lt;path d="M21.64,13a1,1,0,0,0-1.05-.14,8.05,8.05,0,0,1-3.37.73A8.15,8.15,0,0,1,9.08,5.49a8.59,8.59,0,0,1,.25-2A1,1,0,0,0,8,2.36,10.14,10.14,0,1,0,22,14.05,1,1,0,0,0,21.64,13Zm-9.5,6.69A8.14,8.14,0,0,1,7.08,5.22v.27A10.15,10.15,0,0,0,17.22,15.63a9.79,9.79,0,0,0,2.1-.22A8.11,8.11,0,0,1,12.14,19.73Z" /&amp;gt;
    &amp;lt;/svg&amp;gt;
&amp;lt;/label&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;now you can running your dev server and using the that input checkbox (or now it is a sun &amp;amp; moon button) to changing between two themes , for me it will change between theme name '&lt;strong&gt;light&lt;/strong&gt;' and '&lt;strong&gt;dark&lt;/strong&gt;'&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxjterjtsts5wskxtkp0q.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxjterjtsts5wskxtkp0q.gif" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;BUT!!&lt;/u&gt;&lt;/strong&gt; you will notice that while we reload or refresh the page from a dark theme it will be reloaded back to a default theme that we has been set in &lt;code&gt;html&lt;/code&gt; tag from previously &lt;/p&gt;




&lt;h2&gt;
  
  
  Made theme persistent
&lt;/h2&gt;

&lt;p&gt;firstly I will introduce you to a basically way to persist a theme by using cookie and &lt;code&gt;onMount&lt;/code&gt; function of svelte if self&lt;/p&gt;

&lt;p&gt;let copy a code below and paste it in your current component&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script&amp;gt;
    import { onMount } from 'svelte';

    let isDark = false;
    onMount(() =&amp;gt; {
        let decodedCookie = decodeURIComponent(document.cookie);
        let ca = decodedCookie.split(';');
        const cookiesObject = ca.map((cookie) =&amp;gt; {
          const [name, value] = cookie.split('=');
          return { name, value };
        });
        const cookieIsDark = cookiesObject.find(cookie=&amp;gt; cookie.name==='isDark');
        isDark = JSON.parse(cookieIsDark ? cookieIsDark.value : "false") ;
    });


    function setModeCookie() {
        const expirationDate = new Date();
        expirationDate.setDate(expirationDate.getDate() + 365);
        document.cookie = `isDark=${isDark}; expires=${expirationDate.toUTCString()}`;
    }
&amp;lt;/script&amp;gt;

&amp;lt;label class="swap swap-rotate"&amp;gt;
    &amp;lt;!-- this hidden checkbox controls the state --&amp;gt;
    &amp;lt;input
        type="checkbox"
        class="theme-controller"
        value="dark"
    /&amp;gt;

    &amp;lt;!-- sun icon --&amp;gt;
    &amp;lt;svg class="swap-on fill-current w-10 h-10" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&amp;gt;
        &amp;lt;path d="M5.64,17l-.71.71a1,1,0,0,0,0,1.41,1,1,0,0,0,1.41,0l.71-.71A1,1,0,0,0,5.64,17ZM5,12a1,1,0,0,0-1-1H3a1,1,0,0,0,0,2H4A1,1,0,0,0,5,12Zm7-7a1,1,0,0,0,1-1V3a1,1,0,0,0-2,0V4A1,1,0,0,0,12,5ZM5.64,7.05a1,1,0,0,0,.7.29,1,1,0,0,0,.71-.29,1,1,0,0,0,0-1.41l-.71-.71A1,1,0,0,0,4.93,6.34Zm12,.29a1,1,0,0,0,.7-.29l.71-.71a1,1,0,1,0-1.41-1.41L17,5.64a1,1,0,0,0,0,1.41A1,1,0,0,0,17.66,7.34ZM21,11H20a1,1,0,0,0,0,2h1a1,1,0,0,0,0-2Zm-9,8a1,1,0,0,0-1,1v1a1,1,0,0,0,2,0V20A1,1,0,0,0,12,19ZM18.36,17A1,1,0,0,0,17,18.36l.71.71a1,1,0,0,0,1.41,0,1,1,0,0,0,0-1.41ZM12,6.5A5.5,5.5,0,1,0,17.5,12,5.51,5.51,0,0,0,12,6.5Zm0,9A3.5,3.5,0,1,1,15.5,12,3.5,3.5,0,0,1,12,15.5Z" /&amp;gt;
    &amp;lt;/svg&amp;gt;

    &amp;lt;!-- moon icon --&amp;gt;
    &amp;lt;svg class="swap-off fill-current w-10 h-10" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&amp;gt;
        &amp;lt;path d="M21.64,13a1,1,0,0,0-1.05-.14,8.05,8.05,0,0,1-3.37.73A8.15,8.15,0,0,1,9.08,5.49a8.59,8.59,0,0,1,.25-2A1,1,0,0,0,8,2.36,10.14,10.14,0,1,0,22,14.05,1,1,0,0,0,21.64,13Zm-9.5,6.69A8.14,8.14,0,0,1,7.08,5.22v.27A10.15,10.15,0,0,0,17.22,15.63a9.79,9.79,0,0,0,2.1-.22A8.11,8.11,0,0,1,12.14,19.73Z" /&amp;gt;
    &amp;lt;/svg&amp;gt;
&amp;lt;/label&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code while the component is &lt;code&gt;onMount&lt;/code&gt; state it will decoding and get a value of cookie name 'isDark' that data type is boolean and will tell us the page currently in dark mode or not and it value will binding with &lt;code&gt;input&lt;/code&gt; checked state&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;for a first time it will be set to false because page didn't have any cookie yet&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and after we changing a theme with our theme controller, it will calling &lt;code&gt;setModeCookie&lt;/code&gt; function that will set a cookie name '&lt;strong&gt;isDark&lt;/strong&gt;' with value of our '&lt;strong&gt;isDark&lt;/strong&gt;' variable (that suppose to be true by now because we clicked a theme controller and change a page's theme to dark)&lt;/p&gt;

&lt;p&gt;now if you try to refresh or reload the page, the theme will be back into a theme that we has been using before we refresh or reload the page&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq7tj7vzvv7svnhtjaxd8.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq7tj7vzvv7svnhtjaxd8.gif" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;BUT AGAIN!!&lt;/u&gt;&lt;/strong&gt; you will notice some flickering effect after we refresh or reload the page while on 'dark' theme that because the page will be rendered from server side as a 'light' theme and then after 'onMount' is complete the page will get a cookies and set it back to our theme controller to made the page to be in 'dark' theme again  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd4vgaqs9ly51wphgpqrp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd4vgaqs9ly51wphgpqrp.png" alt=" " width="338" height="732"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Stop theme flickering effect!!!
&lt;/h2&gt;

&lt;p&gt;So far we has been using cookie to set a value that telling us, is currently page is in dark mode or not then in Sveltekit we can accessing that cookie on server side too !! &lt;br&gt;
then what we need to do is we will calling that cookie in server side and passing it value back to our page and the page will rendered on value of that passing from server side&lt;/p&gt;

&lt;p&gt;let create new file in &lt;code&gt;src&lt;/code&gt; folder and name it &lt;code&gt;+layout.server.js&lt;/code&gt; and in that file put below code into it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/** @type {import('./$types').LayoutServerLoad} */
export async function load({ cookies }) {
    const isDark = cookies.get('isDark') ?? "false";
    return { isDark };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and put this code below into ModeSwitcher component&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script&amp;gt;
    import { page } from '$app/stores';

    let isDark = JSON.parse($page.data.isDark);

    function setModeCookie() {
        const expirationDate = new Date();
        expirationDate.setDate(expirationDate.getDate() + 365);
        document.cookie = `isDark=${isDark}; expires=${expirationDate.toUTCString()};`;
    }
&amp;lt;/script&amp;gt;

&amp;lt;label class="swap swap-rotate"&amp;gt;
    &amp;lt;!-- this hidden checkbox controls the state --&amp;gt;
    &amp;lt;input
        type="checkbox"
        class="theme-controller"
        value="dark"
    /&amp;gt;

    &amp;lt;!-- sun icon --&amp;gt;
    &amp;lt;svg class="swap-on fill-current w-10 h-10" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&amp;gt;
        &amp;lt;path d="M5.64,17l-.71.71a1,1,0,0,0,0,1.41,1,1,0,0,0,1.41,0l.71-.71A1,1,0,0,0,5.64,17ZM5,12a1,1,0,0,0-1-1H3a1,1,0,0,0,0,2H4A1,1,0,0,0,5,12Zm7-7a1,1,0,0,0,1-1V3a1,1,0,0,0-2,0V4A1,1,0,0,0,12,5ZM5.64,7.05a1,1,0,0,0,.7.29,1,1,0,0,0,.71-.29,1,1,0,0,0,0-1.41l-.71-.71A1,1,0,0,0,4.93,6.34Zm12,.29a1,1,0,0,0,.7-.29l.71-.71a1,1,0,1,0-1.41-1.41L17,5.64a1,1,0,0,0,0,1.41A1,1,0,0,0,17.66,7.34ZM21,11H20a1,1,0,0,0,0,2h1a1,1,0,0,0,0-2Zm-9,8a1,1,0,0,0-1,1v1a1,1,0,0,0,2,0V20A1,1,0,0,0,12,19ZM18.36,17A1,1,0,0,0,17,18.36l.71.71a1,1,0,0,0,1.41,0,1,1,0,0,0,0-1.41ZM12,6.5A5.5,5.5,0,1,0,17.5,12,5.51,5.51,0,0,0,12,6.5Zm0,9A3.5,3.5,0,1,1,15.5,12,3.5,3.5,0,0,1,12,15.5Z" /&amp;gt;
    &amp;lt;/svg&amp;gt;

    &amp;lt;!-- moon icon --&amp;gt;
    &amp;lt;svg class="swap-off fill-current w-10 h-10" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&amp;gt;
        &amp;lt;path d="M21.64,13a1,1,0,0,0-1.05-.14,8.05,8.05,0,0,1-3.37.73A8.15,8.15,0,0,1,9.08,5.49a8.59,8.59,0,0,1,.25-2A1,1,0,0,0,8,2.36,10.14,10.14,0,1,0,22,14.05,1,1,0,0,0,21.64,13Zm-9.5,6.69A8.14,8.14,0,0,1,7.08,5.22v.27A10.15,10.15,0,0,0,17.22,15.63a9.79,9.79,0,0,0,2.1-.22A8.11,8.11,0,0,1,12.14,19.73Z" /&amp;gt;
    &amp;lt;/svg&amp;gt;
&amp;lt;/label&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then if you see a code in &lt;code&gt;+layout.server.js&lt;/code&gt; we will try to get a value of cookie with name 'isDark' and if it not exist just passing "false" as a string and made our ModeSwitcher component receiving that value by using   &lt;code&gt;import { page } from '$app/stores';&lt;/code&gt; this will get a store of page that we will need to subscribe and call it data by &lt;code&gt;$page.data.isDark&lt;/code&gt; , last but not less we will set that value back to ModeSwitcher component 's variable name 'isDark' and that variable is got binding on our input checkbox of Theme Controller&lt;/p&gt;

&lt;p&gt;that mean while page is rendered, a 'isDark' value will set into a value of our cookie that passing by server side and then it will rendered to correctly theme that suppose to be show in the page with out flickering effect at all&lt;/p&gt;

</description>
      <category>sveltekit</category>
      <category>svelte</category>
      <category>daisyui</category>
      <category>tailwindcss</category>
    </item>
    <item>
      <title>Deploying Sveltekit on IIS !</title>
      <dc:creator>Nutchapon Makelai</dc:creator>
      <pubDate>Sat, 15 Jul 2023 05:34:23 +0000</pubDate>
      <link>https://dev.to/nnutnonn/deploying-sveltekit-on-iis--5gf6</link>
      <guid>https://dev.to/nnutnonn/deploying-sveltekit-on-iis--5gf6</guid>
      <description>&lt;p&gt;This is will be long article because it a self note for deploying Sveltekit project (as node project) on IIS version 10.&lt;br&gt;
For a while I searching thru the internet and asking in &lt;a href="https://discord.com/invite/svelte" rel="noopener noreferrer"&gt;svelte discord&lt;/a&gt; (so good community , if you're svelter don't miss to join in) I found out it have little information about how to deploying Sveltekit on IIS , may be I've so many conditions and requirements to made Sveltekit project working on my IIS server.&lt;/p&gt;


&lt;h2&gt;
  
  
  Conditions and Requirements
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;running with &lt;u&gt;one&lt;/u&gt; port and separate each project by &lt;u&gt;sub-directory.&lt;/u&gt;&lt;br&gt;
&lt;strong&gt;&lt;u&gt;ex.&lt;/u&gt;&lt;/strong&gt;&lt;br&gt;
projectA ==&amp;gt;  &lt;code&gt;https://my.testsites.com:443/projectA&lt;/code&gt;&lt;br&gt;
projectB ==&amp;gt;  &lt;code&gt;https://my.testsites.com:443/projectB&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Need to be Server side rendering (SSR) which is Sveltekit project &lt;a href="https://kit.svelte.dev/docs/page-options#ssr" rel="noopener noreferrer"&gt;suppose to be&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Any form actions are not blocked by Cross-site Request Forgery (CSRF) &lt;a href="https://kit.svelte.dev/docs/configuration#csrf" rel="noopener noreferrer"&gt;protection of Sveltekit project&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;express.js on sveltekit project&lt;/li&gt;
&lt;li&gt;node.js (recommend &lt;a href="https://nodejs.org/en" rel="noopener noreferrer"&gt;LTS version&lt;/a&gt;) on IIS server globally install&lt;/li&gt;
&lt;li&gt;some demo Sveltekit project, Let using &lt;a href="https://kit.svelte.dev/docs/creating-a-project" rel="noopener noreferrer"&gt;Sveltekit demo project&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;IIS Services -- &lt;a href="https://www.itechguides.com/how-to-install-iis-in-windows-11/#:~:text=How%20Do%20I%20Enable%20IIS,Then%20click%20the%20OK%20button." rel="noopener noreferrer"&gt;how to install IIS&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;after install IIS&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/Azure/iisnode" rel="noopener noreferrer"&gt;iisnode &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.iis.net/downloads/microsoft/url-rewrite" rel="noopener noreferrer"&gt;urlrewrite&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  How to step by step
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;run &lt;code&gt;npm i&lt;/code&gt; in your sveltekit project folder&lt;/li&gt;
&lt;li&gt;installing additional dependencies

&lt;ul&gt;
&lt;li&gt;adapter-node for sveltekit &lt;code&gt;npm i -D @sveltejs/adapter-node&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;dotenv &lt;code&gt;npm i dotenv&lt;/code&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;setup &lt;code&gt;.env&lt;/code&gt; file in your root folder of your project and put this in your &lt;code&gt;.env&lt;/code&gt; file
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ORIGIN=http://localhost:PORT_OF_SITES
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;while &lt;code&gt;PORT_OF_SITES&lt;/code&gt; will be your port number of IIS site you want to deploy to let say it is 443 then it will be&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ORIGIN=http://localhost:443
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;this will be using after we have deploy Svletekit project to IIS and prevent CSRF blocked after any form actions&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In root folder of your project find &lt;code&gt;svelte.config.js&lt;/code&gt; and adding adapter-node and set base path to made it support a sub-directory in Sveltekit, let change all code inside like this
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import adapter from '@sveltejs/adapter-node';

export default {
    kit: {
        adapter: adapter(),
        paths: {
            relative: false,
            base: '/NAME_OF_SUB-DIRECTORY'
        }
    }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;while &lt;code&gt;NAME_OF_SUB-DIRECTORY&lt;/code&gt; will specifies where your app is served from and allows the app to live on a non-root path&lt;br&gt;
&lt;strong&gt;&lt;u&gt;ex.&lt;/u&gt;&lt;/strong&gt; you want your site address like &lt;code&gt;https://my.sites.com/svelteiis&lt;/code&gt;  then &lt;code&gt;svelte.config.js&lt;/code&gt; code will be like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import adapter from '@sveltejs/adapter-node';

export default {
    kit: {
        adapter: adapter(),
        paths: {
            relative: false,
            base: '/svelteiis'
        }
    }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;after we adding adapter-node and adding base path we need to prepend all root-relative links with the &lt;code&gt;base&lt;/code&gt; value &lt;em&gt;&lt;u&gt;or they will point to the root of your domain, not your &lt;code&gt;base&lt;/code&gt; path&lt;/u&gt;&lt;/em&gt; (&lt;a href="https://kit.svelte.dev/docs/configuration#paths" rel="noopener noreferrer"&gt;this is how the Sveltekit and browser work&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;in &lt;code&gt;src\routes\Header.svelte&lt;/code&gt;, &lt;code&gt;src\routes\about\+page.svelte&lt;/code&gt; and  &lt;code&gt;src\routes\sverdle\+page.svelte&lt;/code&gt; we will adding &lt;code&gt;import { base } from '$app/paths';&lt;/code&gt; in &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag and adding every &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; tag with &lt;code&gt;{base}&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;&lt;u&gt;ex.&lt;/u&gt;&lt;/strong&gt; &lt;code&gt;&amp;lt;a href="{base}/"&amp;gt;Home&amp;lt;/a&amp;gt;&lt;/code&gt;, &lt;code&gt;{base}/about"&amp;gt;About&amp;lt;/a&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;next we will build our project as a node project by using &lt;code&gt;npm run build&lt;/code&gt; and let adapter-node handle it's job . . . . . after some times you will have a &lt;code&gt;build&lt;/code&gt; folder appear in your root project like image below&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm8sx7x2d96bkbxit8yc0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm8sx7x2d96bkbxit8yc0.png" alt=" raw `build` endraw  folder" width="559" height="554"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;let change side to config our IIS , firstly open our IIS and on your left pane just opening till you seen &lt;code&gt;Default Web Site&lt;/code&gt; just right click on it and click &lt;code&gt;explore&lt;/code&gt; like image below&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgausgmc731f8odytfgyj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgausgmc731f8odytfgyj.png" alt="explore a Default Web Site in IIS" width="405" height="564"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;-it will open a new window of file explorer with path &lt;code&gt;C:\inetpub\wwwroot&lt;/code&gt;(let note this as a &lt;code&gt;wwwroot&lt;/code&gt; folder) after that you can copy a &lt;code&gt;build&lt;/code&gt; folder that we has created earlier in our Sveltekit project folder and let changing it name form &lt;code&gt;build&lt;/code&gt; to a name of what your sub-directory you want &lt;em&gt;&lt;u&gt;that will match with &lt;code&gt;base&lt;/code&gt; path that we config earlier&lt;/u&gt;&lt;/em&gt; or it cause some issue on navigating to your site!&lt;br&gt;
after this step your &lt;code&gt;wwwroot&lt;/code&gt; folder will be like image below&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F71fs7rpo0zcsv8ogj4of.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F71fs7rpo0zcsv8ogj4of.png" alt="wwwroot folder" width="799" height="315"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;**you can deploy your project on new IIS site too by creating a new site in IIS and set physicals path to your deploy folder and bring your &lt;code&gt;build&lt;/code&gt; folder into there and following the step by changing &lt;code&gt;build&lt;/code&gt; folder name.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;next we need to copy 2 files form your root project folder, that is &lt;code&gt;.env&lt;/code&gt; file and &lt;code&gt;package.json&lt;/code&gt; file and bring it to your deploying folder in &lt;code&gt;wwwroot&lt;/code&gt; and running just &lt;code&gt;npm i --omit=dev&lt;/code&gt; in this folder to made node downloading only required dependencies
after running npm creating new &lt;code&gt;web.config&lt;/code&gt; file and adding this code into your &lt;code&gt;web.config&lt;/code&gt; file
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;
&amp;lt;configuration&amp;gt;
  &amp;lt;system.webServer&amp;gt;
    &amp;lt;webSocket enabled="false" /&amp;gt;
    &amp;lt;handlers&amp;gt;
      &amp;lt;add name="iisnode" path="server.cjs" verb="*" modules="iisnode" /&amp;gt;
    &amp;lt;/handlers&amp;gt;
    &amp;lt;iisnode node_env="production" nodeProcessCommandLine="C:\Program Files\nodejs\node.exe" /&amp;gt;
    &amp;lt;rewrite&amp;gt; 
        &amp;lt;rules&amp;gt;             
            &amp;lt;rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true"&amp;gt;
                &amp;lt;match url="^server.cjs\/debug[\/]?" /&amp;gt;
                &amp;lt;conditions logicalGrouping="MatchAll" trackAllCaptures="false" /&amp;gt;
            &amp;lt;/rule&amp;gt;

            &amp;lt;rule name="StaticContent"&amp;gt;
                &amp;lt;conditions logicalGrouping="MatchAll" trackAllCaptures="false" /&amp;gt;
                &amp;lt;action type="Rewrite" url="public{PATH_INFO}" /&amp;gt;
            &amp;lt;/rule&amp;gt;

            &amp;lt;rule name="DynamicContent"&amp;gt;
                &amp;lt;conditions logicalGrouping="MatchAll" trackAllCaptures="false"&amp;gt;
                    &amp;lt;add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" /&amp;gt;
                &amp;lt;/conditions&amp;gt;
                &amp;lt;action type="Rewrite" url="server.cjs" /&amp;gt;
            &amp;lt;/rule&amp;gt; 
        &amp;lt;/rules&amp;gt;
        &amp;lt;outboundRules&amp;gt;
            &amp;lt;rule name="back"&amp;gt;
                &amp;lt;match serverVariable="RESPONSE_Location" pattern="(.*)/server.cjs" /&amp;gt;
                &amp;lt;action type="Rewrite" value="{R:1}" /&amp;gt;
            &amp;lt;/rule&amp;gt;
        &amp;lt;/outboundRules&amp;gt;
    &amp;lt;/rewrite&amp;gt;  
    &amp;lt;defaultDocument&amp;gt;
        &amp;lt;files&amp;gt;
            &amp;lt;add value="server.cjs" /&amp;gt;
        &amp;lt;/files&amp;gt;
    &amp;lt;/defaultDocument&amp;gt;
    &amp;lt;security&amp;gt;
      &amp;lt;requestFiltering&amp;gt;
        &amp;lt;hiddenSegments&amp;gt;
          &amp;lt;remove segment="bin" /&amp;gt;
        &amp;lt;/hiddenSegments&amp;gt;
        &amp;lt;requestLimits maxAllowedContentLength="4294967295" /&amp;gt;
      &amp;lt;/requestFiltering&amp;gt;
    &amp;lt;/security&amp;gt;
    &amp;lt;httpErrors existingResponse="PassThrough" /&amp;gt;
  &amp;lt;/system.webServer&amp;gt;
&amp;lt;/configuration&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;after this config your Sveltekit deploy folder will be like a image below &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F15yjgfv1e6vltlaqnvvz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F15yjgfv1e6vltlaqnvvz.png" alt="in project deploy folder" width="800" height="497"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;last but not least we need to have some JavaScript file that will be running after iisnode calling to our project , that made our project can adjust some environment setting
let create a new file name &lt;code&gt;server.cjs&lt;/code&gt; or any other name but if you change the name you need to put that name into a &lt;code&gt;web.config&lt;/code&gt; file from earlier (try search and replace &lt;code&gt;server.cjs&lt;/code&gt; with your new file's name in &lt;code&gt;web.config&lt;/code&gt;)
after creating a &lt;code&gt;server.cjs&lt;/code&gt; file add this code below to your file
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;require('dotenv').config();
const express = require('express')

import('./handler.js')
    .then((handler) =&amp;gt; {
        const app = express();
        // Custom middleware to make routing case-insensitive
        app.use((req, res, next) =&amp;gt; {
            const urlSegments = req.url.split('/');
            urlSegments[1] = urlSegments[1].toLowerCase();
            req.url = urlSegments.join('/');
            next();
        });

        // let SvelteKit handle everything else, including serving prerendered pages and static assets
        app.use(handler.handler);

        app.listen(process.env.PORT, () =&amp;gt; {
            console.log(
                'app start on port ' + process.env.PORT
            );
        });

    }).catch((err) =&amp;gt; console.error(err));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;this will made your &lt;code&gt;.env&lt;/code&gt; file that you copying from earlier working as aspect and will set your origin of project to prevent CSRF protection from a form actions of the project itself and it will made your site can accessing with case insensitive url at a first sub-directory.&lt;br&gt;
by the way you can disabled case insensitive by comment out below code in server.cjs&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.use((req, res, next) =&amp;gt; {
            const urlSegments = req.url.split('/');
            urlSegments[1] = urlSegments[1].toLowerCase();
            req.url = urlSegments.join('/');
            next();
        }); 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;now inside the project folder in &lt;code&gt;wwwroot&lt;/code&gt; will look like this&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fth11dgdw43ycyke0wb4f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fth11dgdw43ycyke0wb4f.png" alt=" " width="800" height="519"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;after that you can try going to the site that you have deploy by go to &lt;br&gt;
&lt;code&gt;http://localhost/NAME_OF_SUB-DIRECTORY&lt;/code&gt; or &lt;code&gt;http://localhost:YOUR_IIS_PORT/NAME_OF_SUB-DIRECTORY&lt;/code&gt; &lt;br&gt;
and finally you has achieved Sveltekit deploying on IIS !&lt;/p&gt;




&lt;p&gt;If you has any question or suggestion on my walkthrough feel free to giving me a comment below. ;)&lt;/p&gt;

&lt;p&gt;Thanks you&lt;br&gt;
Have a nice day and keep coding&lt;/p&gt;

</description>
      <category>svelte</category>
      <category>javascript</category>
      <category>iis</category>
      <category>sveltekit</category>
    </item>
  </channel>
</rss>
