create-mendix-widget-gleam 1.0.7 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +1 -1
- package/src/index.mjs +46 -1
- package/template/docs/glendix_guide.md +98 -7
- package/template/gleam.toml +1 -1
- package/template/manifest.toml +0 -11
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ my-widget/
|
|
|
27
27
|
editor_preview.gleam # Studio Pro 디자인 뷰 미리보기
|
|
28
28
|
components/
|
|
29
29
|
hello_world.gleam # Hello World 공유 컴포넌트
|
|
30
|
-
gleam.toml # Gleam 프로젝트 설정 (glendix >= 1.
|
|
30
|
+
gleam.toml # Gleam 프로젝트 설정 (glendix >= 1.2.0 의존성 포함)
|
|
31
31
|
CLAUDE.md # AI 어시스턴트용 프로젝트 컨텍스트
|
|
32
32
|
```
|
|
33
33
|
|
package/package.json
CHANGED
package/src/index.mjs
CHANGED
|
@@ -102,6 +102,51 @@ export async function main(args) {
|
|
|
102
102
|
// git이 없어도 계속 진행
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
+
// Gleam → JS 컴파일
|
|
106
|
+
console.log(`\n${BOLD}Gleam 컴파일 중...${RESET}\n`);
|
|
107
|
+
try {
|
|
108
|
+
execSync("gleam build --target javascript", {
|
|
109
|
+
cwd: targetDir,
|
|
110
|
+
stdio: "inherit",
|
|
111
|
+
});
|
|
112
|
+
console.log(`\n${GREEN}✓${RESET} Gleam 컴파일 완료`);
|
|
113
|
+
} catch {
|
|
114
|
+
console.error(
|
|
115
|
+
`\n${YELLOW}⚠ Gleam 컴파일 실패. 프로젝트 디렉토리에서 직접 실행하세요:${RESET}`,
|
|
116
|
+
);
|
|
117
|
+
console.error(` ${CYAN}gleam build --target javascript${RESET}\n`);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// 의존성 설치
|
|
121
|
+
console.log(`\n${BOLD}의존성 설치 중...${RESET}\n`);
|
|
122
|
+
try {
|
|
123
|
+
execSync("gleam run -m glendix/install", {
|
|
124
|
+
cwd: targetDir,
|
|
125
|
+
stdio: "inherit",
|
|
126
|
+
});
|
|
127
|
+
console.log(`\n${GREEN}✓${RESET} 의존성 설치 완료`);
|
|
128
|
+
} catch {
|
|
129
|
+
console.error(
|
|
130
|
+
`\n${YELLOW}⚠ 의존성 설치 실패. 프로젝트 디렉토리에서 직접 실행하세요:${RESET}`,
|
|
131
|
+
);
|
|
132
|
+
console.error(` ${CYAN}gleam run -m glendix/install${RESET}\n`);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// 프로덕션 빌드
|
|
136
|
+
console.log(`\n${BOLD}위젯 빌드 중...${RESET}\n`);
|
|
137
|
+
try {
|
|
138
|
+
execSync("gleam run -m glendix/build", {
|
|
139
|
+
cwd: targetDir,
|
|
140
|
+
stdio: "inherit",
|
|
141
|
+
});
|
|
142
|
+
console.log(`\n${GREEN}✓${RESET} 위젯 빌드 완료`);
|
|
143
|
+
} catch {
|
|
144
|
+
console.error(
|
|
145
|
+
`\n${YELLOW}⚠ 빌드 실패. 프로젝트 디렉토리에서 직접 실행하세요:${RESET}`,
|
|
146
|
+
);
|
|
147
|
+
console.error(` ${CYAN}gleam run -m glendix/build${RESET}\n`);
|
|
148
|
+
}
|
|
149
|
+
|
|
105
150
|
// 완료 메시지
|
|
106
151
|
console.log(`
|
|
107
152
|
${GREEN}${BOLD}프로젝트가 생성되었습니다!${RESET}
|
|
@@ -109,7 +154,6 @@ ${GREEN}${BOLD}프로젝트가 생성되었습니다!${RESET}
|
|
|
109
154
|
${BOLD}다음 단계:${RESET}
|
|
110
155
|
|
|
111
156
|
${CYAN}cd ${names.kebabCase}${RESET}
|
|
112
|
-
${CYAN}gleam run -m glendix/install${RESET} ${DIM}# 의존성 설치${RESET}
|
|
113
157
|
${CYAN}gleam run -m glendix/dev${RESET} ${DIM}# 개발 서버 시작${RESET}
|
|
114
158
|
${CYAN}gleam run -m glendix/build${RESET} ${DIM}# 프로덕션 빌드${RESET}
|
|
115
159
|
`);
|
|
@@ -201,6 +245,7 @@ React:
|
|
|
201
245
|
- \`glendix/react/hook\` — React Hooks (useState, useEffect 등)
|
|
202
246
|
- \`glendix/react/event\` — 이벤트 타입 + 값 추출
|
|
203
247
|
- \`glendix/react/html\` — HTML 태그 편의 함수
|
|
248
|
+
- \`glendix/binding\` — 외부 React 컴포넌트 바인딩
|
|
204
249
|
|
|
205
250
|
Mendix:
|
|
206
251
|
- \`glendix/mendix\` — \`ValueStatus\`, \`ObjectItem\`, Props 접근자
|
|
@@ -45,9 +45,11 @@ glendix = { path = "../glendix" }
|
|
|
45
45
|
```
|
|
46
46
|
|
|
47
47
|
```bash
|
|
48
|
-
|
|
48
|
+
gleam run -m glendix/install
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
+
> `glendix/install`은 패키지 매니저를 자동 감지하여 의존성을 설치하고, `bindings.json`이 있으면 외부 React 컴포넌트 바인딩도 자동 생성합니다.
|
|
52
|
+
|
|
51
53
|
#### 4) 빌드 확인
|
|
52
54
|
|
|
53
55
|
```bash
|
|
@@ -198,11 +200,74 @@ react.none() // React null 반환
|
|
|
198
200
|
|
|
199
201
|
#### 외부 React 컴포넌트 사용
|
|
200
202
|
|
|
203
|
+
`glendix/binding` 모듈로 외부 React 라이브러리를 **`.mjs` 없이** 사용합니다.
|
|
204
|
+
|
|
205
|
+
**1단계: `bindings.json` 작성** (프로젝트 루트)
|
|
206
|
+
|
|
207
|
+
```json
|
|
208
|
+
{
|
|
209
|
+
"recharts": {
|
|
210
|
+
"components": ["PieChart", "Pie", "Cell", "LineChart", "Line",
|
|
211
|
+
"XAxis", "YAxis", "CartesianGrid", "Tooltip", "Legend",
|
|
212
|
+
"ResponsiveContainer"]
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
**2단계: `gleam run -m glendix/install`** 실행 (바인딩 자동 생성)
|
|
218
|
+
|
|
219
|
+
**3단계: 순수 Gleam 래퍼 모듈 작성** (편의용, 선택사항)
|
|
220
|
+
|
|
201
221
|
```gleam
|
|
202
|
-
//
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
222
|
+
// src/chart/recharts.gleam — 순수 Gleam, FFI 없음!
|
|
223
|
+
import glendix/binding
|
|
224
|
+
import glendix/react.{type Component}
|
|
225
|
+
|
|
226
|
+
fn m() { binding.module("recharts") }
|
|
227
|
+
|
|
228
|
+
pub fn pie_chart() -> Component { binding.resolve(m(), "PieChart") }
|
|
229
|
+
pub fn pie() -> Component { binding.resolve(m(), "Pie") }
|
|
230
|
+
pub fn cell() -> Component { binding.resolve(m(), "Cell") }
|
|
231
|
+
pub fn tooltip() -> Component { binding.resolve(m(), "Tooltip") }
|
|
232
|
+
pub fn legend() -> Component { binding.resolve(m(), "Legend") }
|
|
233
|
+
pub fn responsive_container() -> Component {
|
|
234
|
+
binding.resolve(m(), "ResponsiveContainer")
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
**4단계: 위젯에서 사용**
|
|
239
|
+
|
|
240
|
+
```gleam
|
|
241
|
+
import chart/recharts
|
|
242
|
+
import glendix/react
|
|
243
|
+
import glendix/react/prop
|
|
244
|
+
|
|
245
|
+
pub fn my_pie_chart(data) -> react.ReactElement {
|
|
246
|
+
react.component(recharts.responsive_container(),
|
|
247
|
+
prop.new() |> prop.int("width", 400) |> prop.int("height", 300),
|
|
248
|
+
[
|
|
249
|
+
react.component(recharts.pie_chart(), prop.new(), [
|
|
250
|
+
react.component(recharts.pie(),
|
|
251
|
+
prop.new()
|
|
252
|
+
|> prop.any("data", data)
|
|
253
|
+
|> prop.string("dataKey", "value"),
|
|
254
|
+
[],
|
|
255
|
+
),
|
|
256
|
+
react.component(recharts.tooltip(), prop.new(), []),
|
|
257
|
+
react.component(recharts.legend(), prop.new(), []),
|
|
258
|
+
]),
|
|
259
|
+
],
|
|
260
|
+
)
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
래퍼 모듈 없이 직접 사용하는 것도 가능합니다:
|
|
265
|
+
|
|
266
|
+
```gleam
|
|
267
|
+
import glendix/binding
|
|
268
|
+
|
|
269
|
+
let rc = binding.module("recharts")
|
|
270
|
+
react.component(binding.resolve(rc, "PieChart"), props, children)
|
|
206
271
|
```
|
|
207
272
|
|
|
208
273
|
### 3.2 Props 빌더
|
|
@@ -1305,8 +1370,8 @@ pub fn dashboard(props) -> ReactElement {
|
|
|
1305
1370
|
| 문제 | 원인 | 해결 |
|
|
1306
1371
|
|---|---|---|
|
|
1307
1372
|
| `gleam build` 실패: glendix를 찾을 수 없음 | `gleam.toml`의 경로가 잘못됨 | `path = "../glendix"` 경로 확인 |
|
|
1308
|
-
| `react is not defined` | peer dependency 미설치 | `
|
|
1309
|
-
| `Big is not a constructor` | big.js 미설치 | `
|
|
1373
|
+
| `react is not defined` | peer dependency 미설치 | `gleam run -m glendix/install` |
|
|
1374
|
+
| `Big is not a constructor` | big.js 미설치 | `gleam run -m glendix/install` |
|
|
1310
1375
|
|
|
1311
1376
|
### 런타임 에러
|
|
1312
1377
|
|
|
@@ -1315,6 +1380,9 @@ pub fn dashboard(props) -> ReactElement {
|
|
|
1315
1380
|
| `Cannot read property of undefined` | 존재하지 않는 prop 접근 | `get_prop` (Option) 대신 `get_prop_required` 사용 시 prop 이름 확인 |
|
|
1316
1381
|
| `set_value` 호출 시 에러 | read_only 상태에서 값 설정 | `ev.is_editable(attr)` 확인 후 설정 |
|
|
1317
1382
|
| Hook 순서 에러 | 조건부로 Hook 호출 | Hook은 항상 동일한 순서로 호출해야 함 (React Rules of Hooks) |
|
|
1383
|
+
| `바인딩이 생성되지 않았습니다` | `binding_ffi.mjs`가 스텁 상태 | `gleam run -m glendix/install` 실행 |
|
|
1384
|
+
| `바인딩에 등록되지 않은 모듈` | `bindings.json`에 해당 패키지 미등록 | `bindings.json`에 패키지와 컴포넌트 추가 후 재설치 |
|
|
1385
|
+
| `모듈에 없는 컴포넌트` | `bindings.json`의 `components`에 해당 컴포넌트 미등록 | `components` 배열에 추가 후 재설치 |
|
|
1318
1386
|
|
|
1319
1387
|
### 일반적인 실수
|
|
1320
1388
|
|
|
@@ -1361,5 +1429,28 @@ list.map(items, fn(item) {
|
|
|
1361
1429
|
let month = date.month(my_date) // 1~12 (Gleam 기준, 변환 불필요)
|
|
1362
1430
|
```
|
|
1363
1431
|
|
|
1432
|
+
**4. 외부 React 컴포넌트용 `.mjs` 파일을 직접 작성하지 마세요:**
|
|
1433
|
+
|
|
1434
|
+
```gleam
|
|
1435
|
+
// 잘못된 방법 — 수동 FFI 작성
|
|
1436
|
+
// recharts_ffi.mjs를 만들고 @external로 연결하는 것
|
|
1437
|
+
|
|
1438
|
+
// 올바른 방법 — bindings.json + glendix/binding 사용
|
|
1439
|
+
import glendix/binding
|
|
1440
|
+
let rc = binding.module("recharts")
|
|
1441
|
+
let pie = binding.resolve(rc, "PieChart")
|
|
1442
|
+
react.component(pie, props, children)
|
|
1443
|
+
```
|
|
1444
|
+
|
|
1445
|
+
**5. `binding.resolve()`에서 컴포넌트 이름을 snake_case로 바꾸지 마세요:**
|
|
1446
|
+
|
|
1447
|
+
```gleam
|
|
1448
|
+
// 잘못된 예
|
|
1449
|
+
binding.resolve(m(), "pie_chart")
|
|
1450
|
+
|
|
1451
|
+
// 올바른 예 — JavaScript 원본 이름(PascalCase) 그대로 사용
|
|
1452
|
+
binding.resolve(m(), "PieChart")
|
|
1453
|
+
```
|
|
1454
|
+
|
|
1364
1455
|
---
|
|
1365
1456
|
|
package/template/gleam.toml
CHANGED
package/template/manifest.toml
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
# This file was generated by Gleam
|
|
2
|
-
# You typically do not need to edit this file
|
|
3
|
-
|
|
4
|
-
packages = [
|
|
5
|
-
{ name = "gleam_stdlib", version = "0.70.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "86949BF5D1F0E4AC0AB5B06F235D8A5CC11A2DFC33BF22F752156ED61CA7D0FF" },
|
|
6
|
-
{ name = "glendix", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glendix", source = "hex", outer_checksum = "9E1B78EEABCC0193F028BB271C3E60565C587E5E901FE553509ECF38D981B58A" },
|
|
7
|
-
]
|
|
8
|
-
|
|
9
|
-
[requirements]
|
|
10
|
-
gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" }
|
|
11
|
-
glendix = { version = ">= 1.0.0 and < 2.0.0" }
|