λ Όμ : MPA - λ€μ€ νμ΄μ§ μ ν리μΌμ΄μ
λ°λ Όμ : SPA - λ¨μΌ νμ΄μ§ μ ν리μΌμ΄μ
μ’ ν©: HDA - νμ΄νΌλ―Έλμ΄ κ΅¬λ μ ν리μΌμ΄μ
νμ΄νΌλ―Έλμ΄ κ΅¬λ μ ν리μΌμ΄μ (Hypermedia Driven Application, HDA) μν€ν μ²λ μ ν΅μ μΈ λ€μ€ νμ΄μ§ μ ν리μΌμ΄μ (MPA)μ λ¨μμ±κ³Ό μ μ°μ±μ λ¨μΌ νμ΄μ§ μ ν리μΌμ΄μ (SPA)μ ν₯μλ μ¬μ©μ κ²½νκ³Ό κ²°ν©ν μλ‘μ΄/μ€λλ μ κ·Ό λ°©μμ λλ€.
HDA μν€ν μ²λ μΉμ κΈ°μ‘΄ HTML μΈνλΌλ₯Ό νμ₯νμ¬ νμ΄νΌλ―Έλμ΄ κ°λ°μκ° λ κ°λ ₯ν νμ΄νΌλ―Έλμ΄ κ΅¬λ μνΈμμ©μ μμ±ν μ μλλ‘ ν¨μΌλ‘μ¨ μ΄λ¬ν λͺ©νλ₯Ό λ¬μ±ν©λλ€.
REST μν€ν μ²μ μ μ½ κ°λ μ λ°λ₯΄λ©°, λ€μκ³Ό κ°μ λ κ°μ§ μ μ½μ΄ HDA μν€ν μ²λ₯Ό νΉμ§μ§μ΅λλ€:
HDAλ λ λμ νλ‘ νΈμλ μνΈμμ©μ λ¬μ±νκΈ° μν΄ λͺ λ Ήν μ€ν¬λ¦½ν μ΄ μλ μ μΈμ , HTMLμ λ΄μ₯λ λ¬Έλ²μ μ¬μ©ν©λλ€.
HDAλ λΉνμ΄νΌλ―Έλμ΄ νμ(e.g. JSON) λμ **νμ΄νΌλ―Έλμ΄(HTML)**λ‘ μλ²μ μνΈμμ©ν©λλ€.
μ΄ λ κ°μ§ μ μ½μ μ±νν¨μΌλ‘μ¨, HDA μν€ν μ²λ SPA μν€ν μ²κ° κ·Έλ μ§ μμ λ°©μμΌλ‘ μΉμ μλ REST-ful μν€ν μ² λ΄μ λ¨Έλ¬΄λ¦ λλ€.
νΉν, HDAλ νμ΄νΌλ―Έλμ΄κ° μ ν리μΌμ΄μ μνμ μμ§μΌλ‘ μλνλ κ²(HATEOAS)μ κ³μ μ¬μ©νμ§λ§, λλΆλΆμ SPAλ ν΄λΌμ΄μΈνΈ μΈ‘ λͺ¨λΈκ³Ό λ°μ΄ν°(API)λ₯Ό μ¬μ©νκ³ HATEOASλ₯Ό ν¬κΈ°ν©λλ€.
htmxμ μ€μκ° κ²μ μμλ₯Ό κ³ λ €ν΄λ³΄μΈμ:
<h3>
Search Contacts
<span class="htmx-indicator">
<img src="/img/bars.svg"/> Searching...
</span>
</h3>
<input class="form-control" type="search"
name="search" placeholder="Begin Typing To Search Users..."
hx-post="/search"
hx-trigger="keyup changed delay:500ms, search"
hx-target="#search-results"
hx-indicator=".htmx-indicator">
<table class="table">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
</tr>
</thead>
<tbody id="search-results">
</tbody>
</table>
μ΄ UX ν¨ν΄μ μΌλ°μ μΌλ‘ SPAμ μ°κ΄λμ§λ§, μ΄ κ²½μ°λ HTML λ΄μμ μμ ν λ¬μ±λλ©°, HTMLκ³Ό μ‘°νλ₯Ό μ΄λ£Ήλλ€.
μ΄ μμλ HDAμ λ³Έμ§μ μΈ νΉμ§μ ν¨κ³Όμ μΌλ‘ 보μ¬μ€λλ€:
POST
μμ²μ΄ μλ²λ‘ μ μ‘λκ³ , μλ²λ HTMLμ λ°ννλ©°, htmxλ μ΄ HTMLμ DOMμ μ½μ
ν©λλ€.Code-On-Demandλ μΉμ μλ REST-ful μν€ν μ²μ μ νμ μ μ½ μ‘°κ±΄μ λλ€.
λ§μ°¬κ°μ§λ‘, HDA μν€ν μ²λ λ§μ§λ§ μ νμ μ μ½ μ‘°κ±΄μ κ°μ§λλ€:
μ΄κ²μ Roy Fieldingμ΄ μμ μ λ Όλ¬Έμμ μΈκΈν Code-On-Demandμ λν μ°λ €λ₯Ό λ€λ£Ήλλ€:
κ·Έλ¬λ, (Code-On-Demandλ) κ°μμ±μ μ€μ΄λ―λ‘, REST λ΄μμ μ νμ μ μ½μΌ λΏμ λλ€.
μ€ν¬λ¦½ν μ HTML λ΄μ μ§μ λ΄μ₯ν¨μΌλ‘μ¨ κ°μμ±μ΄ ν₯μλλ©°, νλμ μ§μμ± μννΈμ¨μ΄ μ€κ³ μμΉμ μΆ©μ‘±μν΅λλ€.
μ΄ μΈ κ°μ§ μ κ·Ό λ°©μμ μ΄ μΈ λ²μ§Έ μ μ½μ λ§μ‘±μν€λ μ€ν¬λ¦½ν λ°©λ²λ€μ λλ€: hyperscript, AlpineJS λ° VanillaJS (HTML μμμ μ§μ λ΄μ₯λ κ²½μ°).
λ€μμ κ° μ κ·Ό λ°©μμ μμμ λλ€:
<!-- hyperscript -->
<button _="on click toggle .red-border">
Toggle Class
</button>
<!-- Alpine JS -->
<button @click="open = !open" :class="{'red-border' : open, '' : !open}">
Toggle Class
</button>
<!-- VanillaJS -->
<button onclick="this.classList.toggle('red-border')">
Toggle Class
</button>
HDAμμλ νμ΄νΌλ―Έλμ΄(HTML)κ° μ ν리μΌμ΄μ μ ꡬμΆνλ λ° μμ΄ μ£Όμ 맀체μ΄λ―λ‘:
μ€ν¬λ¦½ν μ κΈ°μ‘΄μ νμ΄νΌλ―Έλμ΄(HTML)λ₯Ό 보κ°νμ§λ§, μ΄λ₯Ό λ체νκ±°λ HDAμ κΈ°λ³Έ REST-ful μν€ν μ²λ₯Ό νΌμνμ§ μμ΅λλ€.
λ€μ λΌμ΄λΈλ¬λ¦¬λ κ°λ°μκ° HDAλ₯Ό λ§λ€ μ μλλ‘ λμμ€λλ€:
λ€μ μ€ν¬λ¦½ν λΌμ΄λΈλ¬λ¦¬λ μ μ ν μ¬μ©λ λ HDA μ κ·Ό λ°©μμ 보μν©λλ€:
HDA μν€ν μ²λ λ κ°μ§ μ΄μ μν€ν μ², μ¦ μλμ λ€μ€ νμ΄μ§ μ ν리μΌμ΄μ (MPA) μν€ν μ²μ (μλμ μΌλ‘) μλ‘μ΄ λ¨μΌ νμ΄μ§ μ ν리μΌμ΄μ μν€ν μ²μ μ’ ν©μ λλ€.
μ΄ μν€ν μ²λ λ μν€ν μ²μ μ₯μ μ κ²°ν©νλ €κ³ μλν©λλ€: REST-ful μν€ν μ²λ₯Ό μ¬μ©νλ MPAμ λ¨μμ±κ³Ό μ λ’°μ±, κ·Έλ¦¬κ³ λ§μ κ²½μ° SPAμ λλ±ν μ¬μ©μ κ²½νμ μ 곡ν©λλ€.