Releases: Neojs-framework/Neo-app
feat: stateμ actionsλ₯Ό Store νλλ‘ ν΅ν© (v3.0.0)
v3.0.0
ꡬ쑰 λ³κ²½ (Refactor)
- Store ν΅ν©:
stateμactionsλ₯Ό λ¨μΌ κ°μ²΄λ‘ ν΅ν©νμ¬ μν€ν μ² λ¨μν.
λ§μ΄κ·Έλ μ΄μ κ°μ΄λ
- v2 μ¬μ©μλ€μ κΈ°μ‘΄
state.jsμ κ°μ²΄μactions.jsμ ν¨μλ€μ νλμStoreκ°μ²΄λ‘ ν©μ³μΌ ν©λλ€. - Store κ°μ²΄ λ΄λΆμμ λ°μ΄ν°λ₯Ό μ°Έμ‘°ν λ Store.prop λμ this.propμ μ¬μ©ν΄μΌ ν©λλ€.
feat: ::for λ°λ³΅ λ λλ§ λ° μ€μκ° λ°μ΄ν° λ°μΈλ© ꡬν
π Release Notes: Neo Framework v2.6.0
μ΄λ² v2.6.0 μ λ°μ΄νΈλ Neo νλ μμν¬κ° λ¨μν μ μ λ λλ¬λ₯Ό λμ΄, 'λ°μν λ°μ΄ν° λ°μΈλ©' μμ€ν μ κ°μΆ μ§μ ν νλ μμν¬λ‘ μ§νν λ²μ μ λλ€. "μ΅μνμ λ Έλ ₯μΌλ‘ μ΅λμ κ²°κ³Ό"λΌλ μ² ν μλ, 볡μ‘ν 리μ€νΈ μ²λ¦¬μ μν κ΄λ¦¬λ₯Ό λ¨μ¨μ ν΄κ²°νμ΅λλ€.
π μ£Όμ μ λ°μ΄νΈ (New Features)
::forλ°λ³΅λ¬Έ ꡬν:Storeμ μ μ₯λ λ°°μ΄ λ°μ΄ν°λ₯Ό μννλ©° λμ μΌλ‘ UIλ₯Ό μμ±ν©λλ€.- μ§λ₯ν μ€μ½ν(
loopContext): λ°λ³΅λ¬Έ λ΄λΆμμ$todo,indexλ± νμ¬ λ°μ΄ν°μ μ¦μ μ κ·Όν μ μλ λ‘컬 컨ν μ€νΈλ₯Ό μ§μν©λλ€. - μ€μκ° λ°μ΄ν° λκΈ°ν: UIμμ λ°μν μ΄λ²€νΈκ°
Storeμ μλ³Έ λ°μ΄ν°λ₯Ό μ§μ μμ νκ³ , λ³κ²½ μ¬νμ νλ©΄μ μ¦μ 리λ λλ§ν©λλ€.
π λ²κ·Έ μμ λ° κ°μ (Bug Fixes)
- μ΄λ²€νΈ
thisλ°μΈλ©:on:changeλ± μ΄λ²€νΈ λ°μ μthisκ° ν΄λΉ HTML μμλ₯Ό μ νν κ°λ¦¬ν€μ§ λͺ»νλ λ¬Έμ λ₯Ό.call()λ©μλλ₯Ό μ΄μ©ν΄ ν΄κ²°νμ΅λλ€. - λ‘컬 λ³μ μΈμ μ€λ₯:
renderTemplateμ΄ μ μwindowλ§ νμνλ λ¬Έμ λ₯Ό μμ νμ¬loopContextλ₯Ό μ΅μ°μ μΌλ‘ νμνλλ‘ κ°μ νμ΅λλ€. - Boolean μμ± μ²λ¦¬:
checked,disabledλ± λΆλ¦¬μΈ κ°μ΄ λ¬Έμμ΄("true")λ‘ λ°νλ λ¬Έμ λ₯Ό μ€μ λΆλ¦¬μΈ κ°μΌλ‘ λ³ννμ¬ μ μ©λλλ‘ μμ νμ΅λλ€.
π μ¬μ© μμ (Usage)
@ListContainer:div {
::for(todo in Store.todoList) {
@Task:div {
@Checkbox:input {
::attrs { type: "checkbox", checked: "$todo.completed" }
on:change: todo.completed = this.checked
}
@Title:span { innerHTML: "$todo.text" }
}
}
}
fix(NeoParser): ensure element order by implementing position-based sorting (v2.5.2)
π Bug Fixes
::ifλΈλ‘ λ λλ§ μμ μ€λ₯ μμ : κΈ°μ‘΄ λ²μ μμ::if쑰건문 λΈλ‘μ΄ μΌλ° νκ·Έ(@)λ³΄λ€ λ¬΄μ‘°κ±΄ λΆλͺ¨ μμμ μ΅μλ¨μ λ¨Όμ κ·Έλ €μ§λ λ¬Έμ λ₯Ό ν΄κ²°νμ΅λλ€. μ΄μ μμ±νμ μ½λ μμ κ·Έλλ‘ νλ©΄μ λνλ©λλ€.
π Under the Hood (κΈ°μ μ κ°μ )
- μμΉ κΈ°λ° μ λ ¬ (Position-based Sorting) λμ
: νμκ° νκ·Έλ λ©ν λΈλ‘(
::if,::attrs)μ μ€μΊν λ μλ³Έ λ¬Έμμ΄μ μμΉ μΈλ±μ€(_pos)λ₯Ό 'λ²νΈν'μ²λΌ λΆμ¬ν©λλ€. - μΈλ±μ€ λ°λ¦Ό(Index-shifting) λ°©μ§: νμ±μ΄ μλ£λ λΈλ‘μ λ¬Έμμ΄μμ λ¨μν μλΌλ΄λ(
slice) λμ , κ·Έ κΈΈμ΄λ§νΌ 곡백(" ".repeat())μΌλ‘ 보쑴νμ¬ λ€λ°λΌμ€λ νκ·Έλ€μ νμ± μμΉκ° κΌ¬μ΄μ§ μλλ‘ μ΅μ ννμ΅λλ€. - κ²°κ³Όμ μΌλ‘ κ°μ₯ μ μ μ½λ λ³κ²½μΌλ‘ κ°μ₯ μμ μ μΈ νμ± μμλ₯Ό 보μ₯νκ² λμμ΅λλ€.
π» Quick Example
μ΄μ μλμ κ°μ΄ μ½λλ₯Ό μμ±νλ©΄, Message λΈλ‘μ΄ Input λΈλ‘ μλ‘ νμ΄ μ€λ₯΄μ§ μκ³ μ νν Input μλμ λ λλ§λ©λλ€.
@App:div [p-4] {
@Input:input [border, p-2] {
::attrs: { placeholder: "μ
λ ₯μ°½" }
}
::if($Store.state) {
@Message:div [text-blue-500, mt-2] {
innerHTML: "Update! π"
}
}
}
feat: add ::if conditional rendering support
π What's New (μλ‘μ΄ κΈ°λ₯)
::if쑰건문 λ λλ§ μ§μ: μ΄μ μνκ°μ λ°λΌ μ»΄ν¬λνΈλ₯Ό λμ μΌλ‘ κ»λ€ μΌ€ μ μμ΅λλ€.
π» Quick Example (μ¬μ© μμ)
μ΄μ μ»΄ν¬λνΈ λ΄λΆμμ μλμ κ°μ΄ μ§κ΄μ μΌλ‘ 쑰건μ μ μ΄ν μ μμ΅λλ€.
@App:div [p-4] {
::if($Store.loggedIn) {
@WelcomeText:h1 {
innerHTML: "νμν©λλ€, μ μ λ!"
}
}
}
feat: enable $ binding inside ::attrs with proper render order
μΆκ°λ κΈ°λ₯
- ::attrsκΈ°λ₯μ $λ°μΈλ© μΆκ°
@input:input [hello] {
::attrs: {
type: "text",
placeholder: $Store.count
}
}
μμ λ κΈ°λ₯
- 쑰건 λ λλ§
::if
::if ($Store.loggedIn) {
@Profile:div { ... }
}
feat: fix attrs scope by parsing children before meta blocks
μΆκ°λ κΈ°λ₯
- attrsλΈλ‘
- attrs {....}λ₯Ό ν΅ν΄ htmlκ³ μ μμ±μ μ§μ ν μ μκ² λμμ΅λλ€.
μμ κΈ°λ₯
-
μμ± λ°μΈλ©
::attrs { value: $Store.text } -
쑰건 λ λλ§
::if ($Store.loggedIn) { @Profile:div { ... } } -
λ°λ³΅ λ λλ§
::for (item in Store.list) { @Item:li { innerHTML: $item.name } }
feat: add nested children parsing and rendering support
μΆκ°λ κΈ°λ₯
- μμ νμ±
- λ¨μΌ νκ·Έλ§ νμ©λμμ§λ§ μμνκ·Έ μ§μ
- μλ μ¬λλ
- λ°μΈλ©λ λ³μ κ°μ΄ λ°λλλ§λ€ μ μ±κ° μλ μ¬λλ
What's next?
- attrs{....}λ‘ κ³ μ htmlμμ± κ΄λ¦¬
Neo v2.1.0 β Runtime-first UI DSL
π Neo Framework v2.1.0 Release Notes
Release Date: 2026-01
Version: v2.1.0
Package: @junnyontop-pixel/neo-app
β¨ Overview
Neo v2.1.0μ runtime-first UI DSLμ λͺ©νλ‘ ν μμ ν 릴리μ¦μ
λλ€.
μ΄ λ²μ λΆν° Neoλ JavaScript λ‘μ§μ μ§μ λ€λ£¨μ§ μμΌλ©°,
UI μ μΈμλ§ μ§μ€νλ μ΄κ²½λ νλ μμν¬λ‘ μ¬μ μλμμ΅λλ€.
v1μ 볡μ‘ν ꡬ쑰μ μ μ§λ³΄μ νκ³λ₯Ό μμ ν μ κ±°νκ³ ,
λ¨μνκ³ μμΈ‘ κ°λ₯ν λ λλ§ λͺ¨λΈμ μ±ννμ΅λλ€.
π₯ Major Changes
1οΈβ£ Runtime-first Architecture
- λΉλ / μ»΄νμΌ λ¨κ³ μ κ±°
.neoνμΌμ λΈλΌμ°μ μμ μ§μ λ‘λ β νμ± β λ λλ§- Vite, Webpack λ± λΉλ λꡬμ λΉμμ‘΄μ
2οΈβ£ UI / Logic μμ λΆλ¦¬
- UI:
.neo - μν & λ‘μ§: μμ JavaScript (
state.js,actions.js) - Neoλ JavaScriptλ₯Ό ν΄μνκ±°λ λ³ννμ§ μμ
3οΈβ£ Global Store Pattern μ§μ
-
window.StoreκΈ°λ° μ μ μν μ κ·Ό -
ν νλ¦Ώ λ°μΈλ© μ§μ:
innerHTML: "νμ¬ μ«μ: $Store.count" -
μ΄λ²€νΈμμ Store λ©μλ μ§μ νΈμΆ κ°λ₯:
on:click: Store.add()
4οΈβ£ λ¨μνκ³ λͺ νν Render Model
- μλ λ°μν β
- λͺ μμ μ 체 μ¬λ λ β
- μν λ³κ²½ μ
__neoRender()νΈμΆ λ°©μ
Store.count++;
// μλμΌλ‘ main.jsμμ νΈμΆπ§ Design Philosophy
- Neoλ JavaScript νλ μμν¬κ° μλλλ€.
- Neoλ μνλ₯Ό κ΄λ¦¬νμ§ μμ΅λλ€.
- Neoλ UI μ μΈλ§ λ΄λΉν©λλ€.
JavaScriptλ JavaScriptλ΅κ²,
UIλ Neoλ‘ μ μΈνμΈμ.
β οΈ Breaking Changes
#Scriptλ¬Έλ² μ κ±°- μ»΄νμΌλ¬(
neoc) μ¬μ© λ°©μ λ³κ²½ - Neo λ΄λΆ JavaScript 컨ν μ€νΈ/μν κ΄λ¦¬ μ κ±°
- v1 νλ‘μ νΈμ νΈνλμ§ μμ
π Recommended Project Structure
project-root/
βββ src/
β βββ App.neo
β βββ state.js
β βββ actions.js
βββ index.html
βββ vite.config.js (optional)
π Notes
- Neo v2.1.0μ μ€νμ 릴리μ¦μ λλ€.
- λκ·λͺ¨ μ ν리μΌμ΄μ 보λ€λ μκ·λͺ¨ / μ€νμ UI νλ‘μ νΈμ μ ν©ν©λλ€.
- ν₯ν λ²μ μμ μ€μ²© UI, λΆλΆ λ λλ§ λ±μ΄ κ²ν λ μ μμ΅λλ€.
π License
MIT License