CustomElement ใน Svelte3 ง่ายๆ แค่ปลายนิ้ว
thinny
Posted on February 7, 2021
Web components คืออะไร
web component คือชุดของ API แพลตฟอร์มเว็บที่ช่วยให้คุณสร้างแท็ก HTML ที่กำหนดเองใช้ซ้ำได้และห่อหุ้มเพื่อใช้ในเว็บเพจและเว็บแอป คอมโพเนนต์และวิดเจ็ตแบบกำหนดเองขึ้นอยู่กับมาตรฐานส่วนประกอบของเว็บทำงานบนเบราว์เซอร์ที่ทันสมัยและสามารถใช้กับ Library JavaScript ที่เข้ากันได้กับ HTML
ส่วนประกอบของ web component จะประกอบไปด้วย 4 ประการ หลักๆ
- custom Elements specification
- shadow DOM specification
- HTML Template specification
- ES Module specification
web component meta-specification ศึกษาข้อมูลเพิ่มเติมได้ที่
custom HTML tags
class AutonomousButton extends HTMLElement {
...
}
customElements.define("autonomous-button", AutonomousButton);
การเรียกใช้งาน
<autonomous-button>Click Me :)</autonomous-button>
เราสามารถ extends HTMLElements อื่นๆได้ เช่น HTMLButtonElement
class CustomizedButton extends HTMLButtonElement {
...
}
customElements.define("customized-button", CustomizedButton, { extends: "button" });
การเรียกใช้งาน
<button is="customized-button">Click Me :)</button>
Shadow DOM
Shadow DOM เป็นการกำหนดวิธีใช้สไตล์ที่ห่อหุ้มและมาร์กอัปในส่วนประกอบของเว็บ ความสามารถในการซ่อนโครงสร้างมาร์กอัปสไตล์และพฤติกรรมและแยกออกจากโค้ดอื่น ๆ บนเพจเพื่อไม่ให้ส่วนต่างๆขัดแย้งกัน เช่นว่า ถ้าชื่อ styles ภายในและภายนอก เป็นชื่อเดียวกัน ถ้าอยู่ภายใต้ Shadow DOM จะมองเป็นคนละชื่อ และภายใน Shadow DOM จะไม่มี side effect ไปหาภายนอกเช่นกัน
<!--- HTML element --->
<div class="element"></div>
/** attachted shadow DOM */
const header = document.createElement('element');
const shadowRoot = header.attachShadow({mode: 'open'});
shadowRoot.innerHTML = '<h1>Hello Shadow DOM</h1>';
ใช้ const shadowRoot = header.attachShadow({mode: 'open'});
เพื่อ attachShadow เข้าไปใน element
<div class="element">
#shadow-root (open)
<h1>Hello Shadow DOM</h1>
</div>
ES Module
ESM ย่อมาจาก ES Modules เป็นข้อเสนอของ Javascript ในการใช้ระบบโมดูลมาตรฐาน ซึ่งในอนาคต Library ของ Javascript ต้องปรับให้เข้ากับมาตรฐาน ESM ทั้งหมด วิธีสังเกตุการใช้งานจะมี type="module"
ใน tag script
หรือสามารถ import ด้วย นามสกุล .mjs หรือเราสามารถกหนด ใน package.json โดยระบุ type="module"
ก็ได้
/** import syntax */
import "https://example.com/module.mjs";
/** package.json */
{
...
"type": "module"
}
<!-- import module script -->
<script type="module" src="modules/module.js"></script>
<script type="module">
import {awesomeExplosion} from '@awesome-things/awesome-explosion';
</script>
ทีมา integration-with-the-javascript-module-system
เราพอรู้จัก webcomponent กันแล้วใช่ไหมครับ คราวนี้เรามาดูกันว่า ด้วยความเรียบง่ายของ svelte ที่เขียน code ได้สั้นและกระชับ จะเอามาสร้าง webcomponent ได้อย่างไร รับรองว่าแค่กระดิกนิ้ว ก็เสร็จได้โดยง่าย
การทำ CustomElement ใน Svelte
สมมุติเราสร้าง structure ตามภาพนะครับ
📦src
┣ 📂web_components
┃ ┣ 📂Button
┃ ┃ ┣ 📜Button.svelte
┃ ┃ ┗ 📜index.js
┣ 📜App.svelte
┣ 📜main.js
┗ 📜styles.svelte
โค้ดใน component เราจะประมาณนี้
/** Button.svelte */
<svelte:options tag="sv-button" />
<script>
import { onMount } from "svelte";
onMount(() => {
console.log("button web component mounted");
});
const alertClick = () => {
alert("alert Button");
};
</script>
<button on:click={alertClick}>Button</button>
ตัวที่บอกว่า component เราคือ web_component
<svelte:options tag="sv-button" />
ชื่อที่เป็น customElement เราคือ sv-button คำสั่ง svelte:options เป็นคำสั่งคอยบอก compiler ของ svelte ว่า tag="sv-button"
ทำให้เป็น customElement ให้หน่อย
ที่มา svelte-options
ยังไม่จบแค่นี้ เรายังต้องมา config rollup.config.js อีกเล็กน้อย
/** rollup.config.js */
import svelte from "rollup-plugin-svelte";
import path from "path";
let basePath = path.join(__dirname, "./src/web_components");
export default {
input: `${basePath}/Button/Button.svelte`,
output: {
format: "es",
dir: "public/build",
},
...
plugins:[
svelte({
compilerOptions: {
customElement: true
}
}),
]
}
จากภาพด้านบนเราจะเห็นว่า เรามีการ รับ input input: ${basePath}/Button/Button.svelte
แล้วมีการกำหนด output เป็น ESM format ซึ่งทำให้ไฟล์ webcomponent ของเราเป็นไปมาตรฐานของ. web component spec กำหนดปลายทางไปที่ dir: "public/build"
จากนั้นเราลอง build ดูจะได้โครงสร้างประมาณนี้ ตัวที่บอกให้ build component ธรรมดาเป็น web component คือ customElement: true
แต่ว่าต้องไปกำหนด svelte:options ด้วยนะ ใน component ที่เราต้องการ
จะเห็นว่าโครงสร้างมันอยู่ในระดับเดียวกันหมด ถ้ามา component หลายตัวคงวุ่นวายน่าดู งั้นเรามาจะระเบียบโครงสร้างหลัง Build กันใหม่
import multiInput from "rollup-plugin-multi-input";
export default {
...
plugins: [
...,
multiInput({
relative: "src/",
transformOutputPath: (output, input) => {
return output;
},
}),
],
}
เมื่อเพิ่ม plugin นี้เข้าไปมันจะ build โครงสร้างให้เป็นไปตาม src ที่เราได้ทำเอาไว้ มาลอง build กันดูอีกรอบ
พอเรามาแกะโครงสร้าง web component ที่ผ่านการ build มาแล้ว
จะเห็นมีการ ทำ customElement ตาม spec ของ web component
แถมยังมีการ export component ออกมาตาม ESM syntax ด้วย ถ้ายังนั้นก็หมายความเราสามารถเอาไป import ให้ใช้งานได้ เพราะ modern browser รู้จัก syntax แบบนี้อยู่แล้ว
เวลาใช้ก็ import web component ที่เราได้ build ไว้นะครับ
<script type="module" defer src='/build/web_components/Button/Button.js'></script>
ที่สำคัญอย่าลืม type="module"
นะครับ เดี่ยวมันจะด่าเรา
ส่วนตอนจะเรียกใช้ก้แค่ ใส่ชื่อ cutomElement เขาไปได้เลยครับ
<sv-button></sv-button>
พอได้ตามที่ต้องการแล้ว ถึงเวลารัน yarn start/ npm run start
จากนั้น ลองกดไปที่ปุ่ม 1 ครั้งครับมีการ alert เป็นไปตามที่เราได้เขียนไว้เลยครับ
const alertClick = () => {
alert("alert Button");
};
เพียงเท่านี้เราก้ได้ webcomponent ที่เขียนจาก svelte มาใช้แล้วครับ
จะเห็นว่า การสร้าง component ธรรมดา จนกลายมาเป็น web component ที่พร้อมใช้งาน ผ่านการ config น้อยมาก ง่ายมากด้วย นี่ยังไม่ได้พูดถึงการ build webcomponent แบบหลายไฟล์รวมกัน ซึ่ง javascript framework ตัวอื่นทำได้ยากมากกว่าจะได้ web component มาใช้งานอันนึง บางทีอาจจะต้องเอา component มา wrap อีก นั่นเป็นเพราะว่าด้วยข้อจำกัดของ javascript ด้วย
svelte จึงเป็นทางเลือกอีกทางหนึ่ง ที่เหมาะสำหรับนักพัฒนาที่จะเอามาทำเป็น webcomponent แจกจ่าย หรือใช้งานภายในองค์กร เพราะเขียนโค้ดน้อยมาก config ก็ไม่ยากเลย
ขอบคุณที่ท่านที่อ่านมาจนจบ ฝากกด Subscribe กด Share link ด้วยนะครับ
สำหรับใครที่อ่านแล้วยังไม่เข้าใจ แล้วอยากเรียนรู้ svelte. ตั้งแต่เริ่ม แบบ step by step สามารถศึกษาเพิ่มเติมได้ที่
Posted on February 7, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.