jac-client 0.2.0__py3-none-any.whl → 0.2.2__py3-none-any.whl
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.
- jac_client/docs/README.md +50 -20
- jac_client/docs/advanced-state.md +13 -14
- jac_client/docs/asset-serving/intro.md +209 -0
- jac_client/docs/assets/pipe_line-v2.svg +32 -0
- jac_client/docs/file-system/app.jac.md +121 -0
- jac_client/docs/file-system/backend-frontend.md +217 -0
- jac_client/docs/file-system/intro.md +72 -0
- jac_client/docs/file-system/nested-imports.md +348 -0
- jac_client/docs/guide-example/intro.md +11 -13
- jac_client/docs/guide-example/step-01-setup.md +30 -20
- jac_client/docs/guide-example/step-02-components.md +24 -24
- jac_client/docs/guide-example/step-03-styling.md +24 -24
- jac_client/docs/guide-example/step-04-todo-ui.md +17 -17
- jac_client/docs/guide-example/step-05-local-state.md +23 -23
- jac_client/docs/guide-example/step-06-events.md +23 -24
- jac_client/docs/guide-example/step-07-effects.md +27 -28
- jac_client/docs/guide-example/step-08-walkers.md +23 -23
- jac_client/docs/guide-example/step-09-authentication.md +18 -18
- jac_client/docs/guide-example/step-10-routing.md +20 -21
- jac_client/docs/guide-example/step-11-final.md +34 -35
- jac_client/docs/imports.md +4 -5
- jac_client/docs/lifecycle-hooks.md +12 -13
- jac_client/docs/routing.md +21 -22
- jac_client/docs/styling/intro.md +249 -0
- jac_client/docs/styling/js-styling.md +367 -0
- jac_client/docs/styling/material-ui.md +341 -0
- jac_client/docs/styling/pure-css.md +299 -0
- jac_client/docs/styling/sass.md +403 -0
- jac_client/docs/styling/styled-components.md +395 -0
- jac_client/docs/styling/tailwind.md +298 -0
- jac_client/examples/all-in-one/.babelrc +9 -0
- jac_client/examples/all-in-one/README.md +16 -0
- jac_client/examples/all-in-one/app.jac +426 -0
- jac_client/examples/all-in-one/assets/burger.png +0 -0
- jac_client/examples/all-in-one/button.jac +7 -0
- jac_client/examples/all-in-one/components/button.jac +7 -0
- jac_client/examples/all-in-one/package.json +29 -0
- jac_client/examples/all-in-one/styles.css +26 -0
- jac_client/examples/all-in-one/vite.config.js +28 -0
- jac_client/examples/asset-serving/css-with-image/.babelrc +9 -0
- jac_client/examples/asset-serving/css-with-image/README.md +91 -0
- jac_client/examples/asset-serving/css-with-image/app.jac +88 -0
- jac_client/examples/asset-serving/css-with-image/assets/burger.png +0 -0
- jac_client/examples/asset-serving/css-with-image/package.json +28 -0
- jac_client/examples/asset-serving/css-with-image/styles.css +26 -0
- jac_client/examples/asset-serving/css-with-image/vite.config.js +28 -0
- jac_client/examples/asset-serving/image-asset/.babelrc +9 -0
- jac_client/examples/asset-serving/image-asset/README.md +119 -0
- jac_client/examples/asset-serving/image-asset/app.jac +55 -0
- jac_client/examples/asset-serving/image-asset/assets/burger.png +0 -0
- jac_client/examples/asset-serving/image-asset/package.json +28 -0
- jac_client/examples/asset-serving/image-asset/styles.css +26 -0
- jac_client/examples/asset-serving/image-asset/vite.config.js +28 -0
- jac_client/examples/asset-serving/import-alias/.babelrc +9 -0
- jac_client/examples/asset-serving/import-alias/README.md +83 -0
- jac_client/examples/asset-serving/import-alias/app.jac +111 -0
- jac_client/examples/asset-serving/import-alias/assets/burger.png +0 -0
- jac_client/examples/asset-serving/import-alias/package.json +28 -0
- jac_client/examples/asset-serving/import-alias/vite.config.js +28 -0
- jac_client/examples/basic/app.jac +14 -9
- jac_client/examples/basic/package.json +1 -1
- jac_client/examples/basic/vite.config.js +0 -1
- jac_client/examples/basic-auth/package.json +1 -1
- jac_client/examples/basic-auth/vite.config.js +0 -1
- jac_client/examples/basic-auth-with-router/package.json +1 -1
- jac_client/examples/basic-auth-with-router/vite.config.js +0 -1
- jac_client/examples/basic-full-stack/package.json +1 -1
- jac_client/examples/basic-full-stack/vite.config.js +0 -1
- jac_client/examples/css-styling/js-styling/.babelrc +9 -0
- jac_client/examples/css-styling/js-styling/README.md +183 -0
- jac_client/examples/css-styling/js-styling/app.jac +84 -0
- jac_client/examples/css-styling/js-styling/package.json +28 -0
- jac_client/examples/css-styling/js-styling/styles.js +100 -0
- jac_client/examples/css-styling/js-styling/vite.config.js +27 -0
- jac_client/examples/css-styling/material-ui/.babelrc +9 -0
- jac_client/examples/css-styling/material-ui/README.md +16 -0
- jac_client/examples/css-styling/material-ui/app.jac +122 -0
- jac_client/examples/css-styling/material-ui/package.json +32 -0
- jac_client/examples/css-styling/material-ui/vite.config.js +27 -0
- jac_client/examples/css-styling/pure-css/.babelrc +9 -0
- jac_client/examples/css-styling/pure-css/README.md +16 -0
- jac_client/examples/css-styling/pure-css/app.jac +64 -0
- jac_client/examples/css-styling/pure-css/package.json +28 -0
- jac_client/examples/css-styling/pure-css/styles.css +111 -0
- jac_client/examples/css-styling/pure-css/vite.config.js +27 -0
- jac_client/examples/css-styling/sass-example/.babelrc +9 -0
- jac_client/examples/css-styling/sass-example/README.md +16 -0
- jac_client/examples/css-styling/sass-example/app.jac +64 -0
- jac_client/examples/css-styling/sass-example/package.json +29 -0
- jac_client/examples/css-styling/sass-example/styles.scss +153 -0
- jac_client/examples/css-styling/sass-example/vite.config.js +27 -0
- jac_client/examples/css-styling/styled-components/.babelrc +9 -0
- jac_client/examples/css-styling/styled-components/README.md +16 -0
- jac_client/examples/css-styling/styled-components/app.jac +71 -0
- jac_client/examples/css-styling/styled-components/package.json +29 -0
- jac_client/examples/css-styling/styled-components/styled.js +90 -0
- jac_client/examples/css-styling/styled-components/vite.config.js +27 -0
- jac_client/examples/css-styling/tailwind-example/.babelrc +9 -0
- jac_client/examples/css-styling/tailwind-example/README.md +16 -0
- jac_client/examples/css-styling/tailwind-example/app.jac +63 -0
- jac_client/examples/css-styling/tailwind-example/global.css +1 -0
- jac_client/examples/css-styling/tailwind-example/package.json +30 -0
- jac_client/examples/css-styling/tailwind-example/vite.config.js +29 -0
- jac_client/examples/full-stack-with-auth/app.jac +20 -33
- jac_client/examples/full-stack-with-auth/package.json +1 -1
- jac_client/examples/full-stack-with-auth/vite.config.js +0 -1
- jac_client/examples/little-x/app.jac +327 -218
- jac_client/examples/little-x/submit-button.jac +1 -1
- jac_client/examples/nested-folders/nested-advance/.babelrc +9 -0
- jac_client/examples/nested-folders/nested-advance/ButtonRoot.jac +11 -0
- jac_client/examples/nested-folders/nested-advance/README.md +77 -0
- jac_client/examples/nested-folders/nested-advance/app.jac +35 -0
- jac_client/examples/nested-folders/nested-advance/level1/ButtonSecondL.jac +19 -0
- jac_client/examples/nested-folders/nested-advance/level1/Card.jac +43 -0
- jac_client/examples/nested-folders/nested-advance/level1/level2/ButtonThirdL.jac +25 -0
- jac_client/examples/nested-folders/nested-advance/package.json +29 -0
- jac_client/examples/nested-folders/nested-advance/vite.config.js +28 -0
- jac_client/examples/nested-folders/nested-basic/.babelrc +9 -0
- jac_client/examples/nested-folders/nested-basic/README.md +183 -0
- jac_client/examples/nested-folders/nested-basic/app.jac +13 -0
- jac_client/examples/nested-folders/nested-basic/app.js +7 -0
- jac_client/examples/nested-folders/nested-basic/button.jac +7 -0
- jac_client/examples/nested-folders/nested-basic/components/button.jac +7 -0
- jac_client/examples/nested-folders/nested-basic/package.json +28 -0
- jac_client/examples/nested-folders/nested-basic/vite.config.js +27 -0
- jac_client/examples/with-router/app.jac +1 -1
- jac_client/examples/with-router/package.json +1 -1
- jac_client/examples/with-router/vite.config.js +0 -1
- jac_client/plugin/cli.py +7 -2
- jac_client/plugin/client.py +68 -5
- jac_client/plugin/client_runtime.jac +1 -1
- jac_client/plugin/vite_client_bundle.py +162 -14
- jac_client/tests/__init__.py +0 -1
- jac_client/tests/fixtures/basic-app/app.jac +7 -2
- jac_client/tests/fixtures/cl_file/app.cl.jac +48 -0
- jac_client/tests/fixtures/cl_file/app.jac +15 -0
- jac_client/tests/fixtures/client_app_with_antd/app.jac +14 -8
- jac_client/tests/fixtures/js_import/app.jac +19 -15
- jac_client/tests/fixtures/js_import/utils.js +0 -1
- jac_client/tests/fixtures/package.json +1 -1
- jac_client/tests/fixtures/relative_import/app.jac +4 -6
- jac_client/tests/fixtures/relative_import/button.jac +7 -6
- jac_client/tests/fixtures/spawn_test/app.jac +1 -5
- jac_client/tests/fixtures/test_fragments_spread/app.jac +24 -10
- jac_client/tests/test_asset_examples.py +322 -0
- jac_client/tests/test_cl.py +480 -426
- jac_client/tests/test_create_jac_app.py +125 -133
- jac_client/tests/test_it.py +329 -0
- jac_client/tests/test_nested_file.py +374 -0
- {jac_client-0.2.0.dist-info → jac_client-0.2.2.dist-info}/METADATA +2 -2
- jac_client-0.2.2.dist-info/RECORD +171 -0
- jac_client-0.2.0.dist-info/RECORD +0 -72
- {jac_client-0.2.0.dist-info → jac_client-0.2.2.dist-info}/WHEEL +0 -0
- {jac_client-0.2.0.dist-info → jac_client-0.2.2.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
# Nested Folder Imports
|
|
2
|
+
|
|
3
|
+
Jac preserves folder structure during compilation, similar to TypeScript transpilation. This allows you to organize code in nested folders and use relative imports across multiple directory levels.
|
|
4
|
+
|
|
5
|
+
## Folder Structure Preservation
|
|
6
|
+
|
|
7
|
+
When Jac compiles your files, it preserves the folder structure in the `src/` directory:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
Source Structure: Compiled Structure:
|
|
11
|
+
my-app/ src/
|
|
12
|
+
├── app.jac → ├── app.js
|
|
13
|
+
├── ButtonRoot.jac → ├── ButtonRoot.js
|
|
14
|
+
└── level1/ └── level1/
|
|
15
|
+
├── ButtonSecondL.jac → ├── ButtonSecondL.js
|
|
16
|
+
├── Card.jac → ├── Card.js
|
|
17
|
+
└── level2/ └── level2/
|
|
18
|
+
└── ButtonThirdL.jac → └── ButtonThirdL.js
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Relative Import Syntax
|
|
22
|
+
|
|
23
|
+
Jac uses dot notation for relative imports:
|
|
24
|
+
|
|
25
|
+
- **Single dot (`.`)** - Current directory
|
|
26
|
+
- **Double dot (`..`)** - Parent directory (one level up)
|
|
27
|
+
- **Triple dot (`...`)** - Two levels up
|
|
28
|
+
- **Multiple dots** - Continue going up the directory tree
|
|
29
|
+
- **Dot notation after dots** - Go down into subdirectories (e.g., `.level2`)
|
|
30
|
+
|
|
31
|
+
## Import Patterns by Directory Level
|
|
32
|
+
|
|
33
|
+
### Root Level Imports
|
|
34
|
+
|
|
35
|
+
From the root directory, you can import from nested folders:
|
|
36
|
+
|
|
37
|
+
```jac
|
|
38
|
+
# app.jac (root level)
|
|
39
|
+
|
|
40
|
+
# Import from root
|
|
41
|
+
cl import from .ButtonRoot {
|
|
42
|
+
ButtonRoot
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
# Import from level1
|
|
46
|
+
cl import from .level1.ButtonSecondL {
|
|
47
|
+
ButtonSecondL
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
# Import from level1/level2
|
|
51
|
+
cl import from .level1.level2.ButtonThirdL {
|
|
52
|
+
ButtonThirdL
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
# Import from level1
|
|
56
|
+
cl import from .level1.Card {
|
|
57
|
+
Card
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Second Level Imports
|
|
62
|
+
|
|
63
|
+
From `level1/`, you can import from root (up) or level2 (down):
|
|
64
|
+
|
|
65
|
+
```jac
|
|
66
|
+
# level1/ButtonSecondL.jac
|
|
67
|
+
|
|
68
|
+
# Import from root (go up one level with ..)
|
|
69
|
+
cl import from ..ButtonRoot {
|
|
70
|
+
ButtonRoot
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
```jac
|
|
75
|
+
# level1/Card.jac
|
|
76
|
+
|
|
77
|
+
# Import from root (go up two levels with ..)
|
|
78
|
+
cl import from ..ButtonRoot {
|
|
79
|
+
ButtonRoot
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
# Import from level2 (go down one level with .level2)
|
|
83
|
+
cl import from .level2.ButtonThirdL {
|
|
84
|
+
ButtonThirdL
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Third Level Imports
|
|
89
|
+
|
|
90
|
+
From `level1/level2/`, you can import from root or parent levels:
|
|
91
|
+
|
|
92
|
+
```jac
|
|
93
|
+
# level1/level2/ButtonThirdL.jac
|
|
94
|
+
|
|
95
|
+
# Import from root (go up three levels with ...)
|
|
96
|
+
cl import from ...ButtonRoot {
|
|
97
|
+
ButtonRoot
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
# Import from second level (go up one level with ..)
|
|
101
|
+
cl import from ..ButtonSecondL {
|
|
102
|
+
ButtonSecondL
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Complete Example
|
|
107
|
+
|
|
108
|
+
Here's a complete example demonstrating nested folder imports:
|
|
109
|
+
|
|
110
|
+
**Project Structure:**
|
|
111
|
+
```
|
|
112
|
+
nested-advance/
|
|
113
|
+
├── app.jac # Root entry point
|
|
114
|
+
├── ButtonRoot.jac # Root level button
|
|
115
|
+
└── level1/
|
|
116
|
+
├── ButtonSecondL.jac # Second level button
|
|
117
|
+
├── Card.jac # Card component (imports from root and level2)
|
|
118
|
+
└── level2/
|
|
119
|
+
└── ButtonThirdL.jac # Third level button
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**app.jac:**
|
|
123
|
+
```jac
|
|
124
|
+
cl import from .ButtonRoot {
|
|
125
|
+
ButtonRoot
|
|
126
|
+
}
|
|
127
|
+
cl import from .level1.ButtonSecondL {
|
|
128
|
+
ButtonSecondL
|
|
129
|
+
}
|
|
130
|
+
cl import from .level1.level2.ButtonThirdL {
|
|
131
|
+
ButtonThirdL
|
|
132
|
+
}
|
|
133
|
+
cl import from .level1.Card {
|
|
134
|
+
Card
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
cl def app() -> any {
|
|
138
|
+
return <div>
|
|
139
|
+
<ButtonRoot />
|
|
140
|
+
<ButtonSecondL />
|
|
141
|
+
<ButtonThirdL />
|
|
142
|
+
<Card />
|
|
143
|
+
</div>;
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**level1/ButtonSecondL.jac:**
|
|
148
|
+
```jac
|
|
149
|
+
cl import from ..ButtonRoot {
|
|
150
|
+
ButtonRoot
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
cl def ButtonSecondL() -> any {
|
|
154
|
+
return <div>
|
|
155
|
+
<Button>Second Level</Button>
|
|
156
|
+
<ButtonRoot />
|
|
157
|
+
</div>;
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**level1/Card.jac:**
|
|
162
|
+
```jac
|
|
163
|
+
# Imports from both above (root) and below (level2)
|
|
164
|
+
cl import from ..ButtonRoot {
|
|
165
|
+
ButtonRoot
|
|
166
|
+
}
|
|
167
|
+
cl import from .level2.ButtonThirdL {
|
|
168
|
+
ButtonThirdL
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
cl def Card() -> any {
|
|
172
|
+
return <div>
|
|
173
|
+
<ButtonRoot />
|
|
174
|
+
<ButtonThirdL />
|
|
175
|
+
</div>;
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
**level1/level2/ButtonThirdL.jac:**
|
|
180
|
+
```jac
|
|
181
|
+
cl import from ...ButtonRoot {
|
|
182
|
+
ButtonRoot
|
|
183
|
+
}
|
|
184
|
+
cl import from ..ButtonSecondL {
|
|
185
|
+
ButtonSecondL
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
cl def ButtonThirdL() -> any {
|
|
189
|
+
return <div>
|
|
190
|
+
<Button>Third Level</Button>
|
|
191
|
+
<ButtonRoot />
|
|
192
|
+
<ButtonSecondL />
|
|
193
|
+
</div>;
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Import Path Reference
|
|
198
|
+
|
|
199
|
+
| Your Location | Target Location | Import Path |
|
|
200
|
+
|--------------|----------------|-------------|
|
|
201
|
+
| `app.jac` (root) | `ButtonRoot.jac` (root) | `.ButtonRoot` |
|
|
202
|
+
| `app.jac` (root) | `level1/ButtonSecondL.jac` | `.level1.ButtonSecondL` |
|
|
203
|
+
| `app.jac` (root) | `level1/level2/ButtonThirdL.jac` | `.level1.level2.ButtonThirdL` |
|
|
204
|
+
| `level1/ButtonSecondL.jac` | `ButtonRoot.jac` (root) | `..ButtonRoot` |
|
|
205
|
+
| `level1/Card.jac` | `ButtonRoot.jac` (root) | `..ButtonRoot` |
|
|
206
|
+
| `level1/Card.jac` | `level2/ButtonThirdL.jac` | `.level2.ButtonThirdL` |
|
|
207
|
+
| `level1/level2/ButtonThirdL.jac` | `ButtonRoot.jac` (root) | `...ButtonRoot` |
|
|
208
|
+
| `level1/level2/ButtonThirdL.jac` | `level1/ButtonSecondL.jac` | `..ButtonSecondL` |
|
|
209
|
+
|
|
210
|
+
## Benefits of Nested Folder Structure
|
|
211
|
+
|
|
212
|
+
1. **Relative imports work correctly**: Folder structure is preserved, so imports resolve properly
|
|
213
|
+
2. **No file name conflicts**: Files with the same name in different folders don't overwrite each other
|
|
214
|
+
3. **Familiar structure**: Organize code in nested folders just like in TypeScript/JavaScript projects
|
|
215
|
+
4. **Consistent with modern tooling**: Matches the behavior of TypeScript, Babel, and other transpilers
|
|
216
|
+
5. **Scalable organization**: Organize large applications into logical folder hierarchies
|
|
217
|
+
|
|
218
|
+
## Best Practices for Nested Folders
|
|
219
|
+
|
|
220
|
+
1. **Organize by feature or component type**: Group related files together
|
|
221
|
+
```
|
|
222
|
+
components/
|
|
223
|
+
├── ui/
|
|
224
|
+
│ ├── Button.jac
|
|
225
|
+
│ └── Card.jac
|
|
226
|
+
├── layout/
|
|
227
|
+
│ ├── Header.jac
|
|
228
|
+
│ └── Footer.jac
|
|
229
|
+
└── features/
|
|
230
|
+
├── TodoList.jac
|
|
231
|
+
└── TodoItem.jac
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
2. **Use consistent naming**: Keep file names descriptive and consistent
|
|
235
|
+
3. **Limit nesting depth**: Avoid going too deep (3-4 levels is usually sufficient)
|
|
236
|
+
4. **Document import patterns**: Comment complex import relationships
|
|
237
|
+
|
|
238
|
+
## Common Patterns
|
|
239
|
+
|
|
240
|
+
### Pattern 1: Component Library Structure
|
|
241
|
+
```
|
|
242
|
+
components/
|
|
243
|
+
├── ui/
|
|
244
|
+
│ ├── Button.jac
|
|
245
|
+
│ └── Input.jac
|
|
246
|
+
├── forms/
|
|
247
|
+
│ ├── LoginForm.jac
|
|
248
|
+
│ └── SignupForm.jac
|
|
249
|
+
└── layout/
|
|
250
|
+
├── Header.jac
|
|
251
|
+
└── Sidebar.jac
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
**Usage:**
|
|
255
|
+
```jac
|
|
256
|
+
# From root
|
|
257
|
+
cl import from .components.ui.Button { Button }
|
|
258
|
+
cl import from .components.forms.LoginForm { LoginForm }
|
|
259
|
+
|
|
260
|
+
# From components/ui/Button.jac importing from forms
|
|
261
|
+
cl import from ..forms.LoginForm { LoginForm }
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Pattern 2: Feature-Based Structure
|
|
265
|
+
```
|
|
266
|
+
features/
|
|
267
|
+
├── auth/
|
|
268
|
+
│ ├── Login.jac
|
|
269
|
+
│ └── Signup.jac
|
|
270
|
+
├── todos/
|
|
271
|
+
│ ├── TodoList.jac
|
|
272
|
+
│ └── TodoItem.jac
|
|
273
|
+
└── dashboard/
|
|
274
|
+
├── Dashboard.jac
|
|
275
|
+
└── Stats.jac
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
**Usage:**
|
|
279
|
+
```jac
|
|
280
|
+
# From root
|
|
281
|
+
cl import from .features.auth.Login { Login }
|
|
282
|
+
cl import from .features.todos.TodoList { TodoList }
|
|
283
|
+
|
|
284
|
+
# From features/auth/Login.jac importing from todos
|
|
285
|
+
cl import from ..todos.TodoList { TodoList }
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Pattern 3: Mixed Structure
|
|
289
|
+
```
|
|
290
|
+
app.jac # Root entry
|
|
291
|
+
components/
|
|
292
|
+
├── ui/
|
|
293
|
+
│ └── Button.jac
|
|
294
|
+
utils/
|
|
295
|
+
├── helpers/
|
|
296
|
+
│ └── format.jac
|
|
297
|
+
hooks/
|
|
298
|
+
└── useCounter.jac
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
**Usage:**
|
|
302
|
+
```jac
|
|
303
|
+
# From app.jac
|
|
304
|
+
cl import from .components.ui.Button { Button }
|
|
305
|
+
cl import from .utils.helpers.format { capitalize }
|
|
306
|
+
cl import from .hooks.useCounter { useCounter }
|
|
307
|
+
|
|
308
|
+
# From components/ui/Button.jac
|
|
309
|
+
cl import from ...utils.helpers.format { capitalize }
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
## Troubleshooting
|
|
313
|
+
|
|
314
|
+
### Import Not Found
|
|
315
|
+
- Verify the file exists at the expected path
|
|
316
|
+
- Check that the relative path matches the folder structure
|
|
317
|
+
- Ensure file extension is `.jac` (not `.cl.jac` for imports)
|
|
318
|
+
|
|
319
|
+
### Wrong Import Path
|
|
320
|
+
- Count the directory levels between source and target
|
|
321
|
+
- Use `..` for each level up, `.folder` for each level down
|
|
322
|
+
- Start with `.` for current directory imports
|
|
323
|
+
|
|
324
|
+
### File Name Conflicts
|
|
325
|
+
- Use nested folders to avoid conflicts
|
|
326
|
+
- Files with the same name in different folders won't conflict
|
|
327
|
+
- Folder structure is preserved in compiled output
|
|
328
|
+
|
|
329
|
+
## Examples
|
|
330
|
+
|
|
331
|
+
Complete working examples demonstrating nested folder imports:
|
|
332
|
+
|
|
333
|
+
- [`nested-basic/`](../../examples/nested-folders/nested-basic/) - Simple nested folder structure
|
|
334
|
+
- [`nested-advance/`](../../examples/nested-folders/nested-advance/) - Advanced multi-level nesting
|
|
335
|
+
|
|
336
|
+
Run any example:
|
|
337
|
+
|
|
338
|
+
```bash
|
|
339
|
+
cd jac-client/jac_client/examples/nested-folders/<example-name>
|
|
340
|
+
npm install
|
|
341
|
+
jac serve app.jac
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
## Related Documentation
|
|
345
|
+
|
|
346
|
+
- [Backend/Frontend Separation](backend-frontend.md)
|
|
347
|
+
- [Import System](../imports.md)
|
|
348
|
+
- [File System Organization](intro.md)
|
|
@@ -15,19 +15,19 @@ Traditionally, you'd need:
|
|
|
15
15
|
- **SQL** for database
|
|
16
16
|
- **REST APIs** to connect them
|
|
17
17
|
|
|
18
|
-
With **Jac**, you write **everything in one language**, in **one file**!
|
|
18
|
+
With **Jac**, you write **everything in one language**, in **one file**!
|
|
19
19
|
|
|
20
20
|
## What You'll Build
|
|
21
21
|
|
|
22
22
|
By the end of this guide, you'll have a fully functional Todo app with:
|
|
23
23
|
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
-
|
|
24
|
+
- **Beautiful UI** - Modern, responsive interface
|
|
25
|
+
- **User Authentication** - Signup and login
|
|
26
|
+
- **Protected Routes** - Private pages only for logged-in users
|
|
27
|
+
- **Full CRUD** - Create, Read, Update, Delete todos
|
|
28
|
+
- **Real Backend** - Data persists even after refresh
|
|
29
|
+
- **Filtering** - View all, active, or completed todos
|
|
30
|
+
- **Multiple Pages** - Routing without page reloads
|
|
31
31
|
|
|
32
32
|
All of this in approximately **735 lines of Jac code**!
|
|
33
33
|
|
|
@@ -67,8 +67,8 @@ pip install jac-client
|
|
|
67
67
|
|
|
68
68
|
Each step builds on the previous one, gradually creating the complete app. Every step has **two parts**:
|
|
69
69
|
|
|
70
|
-
1.
|
|
71
|
-
2.
|
|
70
|
+
1. ** Part 1: Building the App** - Hands-on coding, building the actual app
|
|
71
|
+
2. ** Part 2: Understanding the Concepts** - Optional deeper knowledge
|
|
72
72
|
|
|
73
73
|
**Want to just build?** Follow only Part 1 of each step and skip all Part 2 sections. You'll still have a working app!
|
|
74
74
|
|
|
@@ -112,6 +112,4 @@ We'll build the app in 11 progressive steps:
|
|
|
112
112
|
|
|
113
113
|
Let's build your first full-stack app!
|
|
114
114
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
115
|
+
**[Continue to Step 1: Project Setup](./step-01-setup.md)**
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# Step 1: Project Setup
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> ** Quick Tip:** Each step has two parts. **Part 1** shows you what to build. **Part 2** explains why it works. Want to just build? Skip all Part 2 sections!
|
|
4
4
|
|
|
5
5
|
In this first step, you'll create your Jac project and understand the basic file structure.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## Part 1: Building the App
|
|
10
10
|
|
|
11
11
|
### Step 1.1: Create Your Project
|
|
12
12
|
|
|
@@ -78,15 +78,15 @@ Open your browser and go to:
|
|
|
78
78
|
http://localhost:8000/page/app
|
|
79
79
|
```
|
|
80
80
|
|
|
81
|
-
You should see "Hello, Jac!" and "My first full-stack app"
|
|
81
|
+
You should see "Hello, Jac!" and "My first full-stack app"
|
|
82
82
|
|
|
83
83
|
---
|
|
84
84
|
|
|
85
|
-
|
|
85
|
+
**⏭ Want to skip the theory?** Jump to [Step 2: First Component](./step-02-components.md)
|
|
86
86
|
|
|
87
87
|
---
|
|
88
88
|
|
|
89
|
-
##
|
|
89
|
+
## Part 2: Understanding the Concepts
|
|
90
90
|
|
|
91
91
|
### What is `cl { ... }`?
|
|
92
92
|
|
|
@@ -99,6 +99,7 @@ cl {
|
|
|
99
99
|
```
|
|
100
100
|
|
|
101
101
|
Think of it like this:
|
|
102
|
+
|
|
102
103
|
- Code **inside** `cl { }` → Runs in the browser (frontend)
|
|
103
104
|
- Code **outside** `cl { }` → Runs on the server (backend)
|
|
104
105
|
|
|
@@ -113,6 +114,7 @@ def app() -> any {
|
|
|
113
114
|
```
|
|
114
115
|
|
|
115
116
|
**Requirements:**
|
|
117
|
+
|
|
116
118
|
- Must be named `app` (by convention)
|
|
117
119
|
- Must return JSX (HTML-like syntax)
|
|
118
120
|
- Located inside `cl { }` block
|
|
@@ -142,19 +144,22 @@ return <div>
|
|
|
142
144
|
```
|
|
143
145
|
|
|
144
146
|
**Key rules:**
|
|
147
|
+
|
|
145
148
|
1. Must have **one root element**
|
|
149
|
+
|
|
146
150
|
```jac
|
|
147
|
-
#
|
|
151
|
+
# Correct
|
|
148
152
|
return <div><h1>Title</h1><p>Text</p></div>;
|
|
149
153
|
|
|
150
|
-
#
|
|
154
|
+
# Wrong (two root elements)
|
|
151
155
|
return <h1>Title</h1><p>Text</p>;
|
|
152
156
|
```
|
|
153
157
|
|
|
154
158
|
2. Self-closing tags need `/`
|
|
159
|
+
|
|
155
160
|
```jac
|
|
156
|
-
<img src="photo.jpg" /> #
|
|
157
|
-
<img src="photo.jpg"> #
|
|
161
|
+
<img src="photo.jpg" /> # Correct
|
|
162
|
+
<img src="photo.jpg"> # Wrong
|
|
158
163
|
```
|
|
159
164
|
|
|
160
165
|
3. Use `{}` to insert Jac code
|
|
@@ -190,22 +195,23 @@ But for this tutorial, we'll keep everything in one file for simplicity.
|
|
|
190
195
|
|
|
191
196
|
---
|
|
192
197
|
|
|
193
|
-
##
|
|
198
|
+
## What You've Learned
|
|
194
199
|
|
|
195
|
-
-
|
|
196
|
-
-
|
|
197
|
-
-
|
|
198
|
-
-
|
|
199
|
-
-
|
|
200
|
-
-
|
|
200
|
+
- How to create a Jac project
|
|
201
|
+
- Project structure basics
|
|
202
|
+
- What `cl { }` means (client-side code)
|
|
203
|
+
- The `def app()` entry point
|
|
204
|
+
- JSX basics (HTML in code)
|
|
205
|
+
- Running your app with `jac serve`
|
|
201
206
|
|
|
202
207
|
---
|
|
203
208
|
|
|
204
|
-
##
|
|
209
|
+
## Common Issues
|
|
205
210
|
|
|
206
211
|
### Issue: `jac: command not found`
|
|
207
212
|
|
|
208
213
|
**Solution**: Install jac-client:
|
|
214
|
+
|
|
209
215
|
```bash
|
|
210
216
|
pip install jac-client
|
|
211
217
|
```
|
|
@@ -213,14 +219,17 @@ pip install jac-client
|
|
|
213
219
|
### Issue: Port 8000 already in use
|
|
214
220
|
|
|
215
221
|
**Solution**: Use a different port:
|
|
222
|
+
|
|
216
223
|
```bash
|
|
217
224
|
jac serve app.jac --port 8080
|
|
218
225
|
```
|
|
226
|
+
|
|
219
227
|
Then visit `http://localhost:8080/page/app`
|
|
220
228
|
|
|
221
229
|
### Issue: Blank page in browser
|
|
222
230
|
|
|
223
231
|
**Check:**
|
|
232
|
+
|
|
224
233
|
- Did you visit `/page/app` (not just `/`)?
|
|
225
234
|
- Check terminal for errors
|
|
226
235
|
- Make sure `app()` has a `return` statement
|
|
@@ -228,13 +237,14 @@ Then visit `http://localhost:8080/page/app`
|
|
|
228
237
|
### Issue: Changes not showing
|
|
229
238
|
|
|
230
239
|
**Solution**:
|
|
240
|
+
|
|
231
241
|
- Stop the server (Ctrl+C)
|
|
232
242
|
- Restart: `jac serve app.jac`
|
|
233
243
|
- Refresh browser
|
|
234
244
|
|
|
235
245
|
---
|
|
236
246
|
|
|
237
|
-
##
|
|
247
|
+
## Quick Exercise
|
|
238
248
|
|
|
239
249
|
Before moving on, try changing the text:
|
|
240
250
|
|
|
@@ -253,8 +263,8 @@ Save, refresh your browser, and see the changes!
|
|
|
253
263
|
|
|
254
264
|
---
|
|
255
265
|
|
|
256
|
-
##
|
|
266
|
+
## Next Step
|
|
257
267
|
|
|
258
268
|
Great! You have a running Jac app. Now let's learn about **components** - the building blocks of any UI.
|
|
259
269
|
|
|
260
|
-
|
|
270
|
+
**[Continue to Step 2: First Component](./step-02-components.md)**
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# Step 2: First Component
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> ** Quick Tip:** Each step has two parts. **Part 1** shows you what to build. **Part 2** explains why it works. Want to just build? Skip all Part 2 sections!
|
|
4
4
|
|
|
5
5
|
In this step, you'll create your first reusable component - a **TodoItem** that displays a single todo.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## Part 1: Building the App
|
|
10
10
|
|
|
11
11
|
### Step 2.1: Create a TodoItem Component
|
|
12
12
|
|
|
@@ -119,11 +119,11 @@ cl {
|
|
|
119
119
|
|
|
120
120
|
---
|
|
121
121
|
|
|
122
|
-
|
|
122
|
+
**⏭ Want to skip the theory?** Jump to [Step 3: Styling](./step-03-styling.md)
|
|
123
123
|
|
|
124
124
|
---
|
|
125
125
|
|
|
126
|
-
##
|
|
126
|
+
## Part 2: Understanding the Concepts
|
|
127
127
|
|
|
128
128
|
### What is a Component?
|
|
129
129
|
|
|
@@ -182,12 +182,12 @@ If there's a bug in how todos display, you know to check `TodoItem`.
|
|
|
182
182
|
**1. Use PascalCase** (first letter capitalized)
|
|
183
183
|
|
|
184
184
|
```jac
|
|
185
|
-
#
|
|
185
|
+
# Correct
|
|
186
186
|
def TodoItem() -> any { ... }
|
|
187
187
|
def UserProfile() -> any { ... }
|
|
188
188
|
def NavigationBar() -> any { ... }
|
|
189
189
|
|
|
190
|
-
#
|
|
190
|
+
# Wrong
|
|
191
191
|
def todoItem() -> any { ... } # camelCase
|
|
192
192
|
def user_profile() -> any { ... } # snake_case
|
|
193
193
|
def navigation-bar() -> any { ... } # kebab-case
|
|
@@ -196,12 +196,12 @@ def navigation-bar() -> any { ... } # kebab-case
|
|
|
196
196
|
**2. Name describes what it does**
|
|
197
197
|
|
|
198
198
|
```jac
|
|
199
|
-
#
|
|
199
|
+
# Good names
|
|
200
200
|
def TodoItem() -> any { ... }
|
|
201
201
|
def LoginForm() -> any { ... }
|
|
202
202
|
def ProductCard() -> any { ... }
|
|
203
203
|
|
|
204
|
-
#
|
|
204
|
+
# Bad names
|
|
205
205
|
def Component1() -> any { ... }
|
|
206
206
|
def Thing() -> any { ... }
|
|
207
207
|
def X() -> any { ... }
|
|
@@ -226,14 +226,14 @@ def TodoItem(props: any) -> any {
|
|
|
226
226
|
**Important**: In React (which Jac uses), components receive props as a **single object**, not individual parameters.
|
|
227
227
|
|
|
228
228
|
```jac
|
|
229
|
-
#
|
|
229
|
+
# Correct way
|
|
230
230
|
def TodoItem(props: any) -> any {
|
|
231
231
|
let text = props.text;
|
|
232
232
|
let done = props.done;
|
|
233
233
|
# ...
|
|
234
234
|
}
|
|
235
235
|
|
|
236
|
-
#
|
|
236
|
+
# Wrong way (won't work)
|
|
237
237
|
def TodoItem(text: str, done: bool) -> any {
|
|
238
238
|
# This doesn't work in React!
|
|
239
239
|
}
|
|
@@ -328,19 +328,19 @@ let myText = "Learn Jac";
|
|
|
328
328
|
|
|
329
329
|
---
|
|
330
330
|
|
|
331
|
-
##
|
|
331
|
+
## What You've Learned
|
|
332
332
|
|
|
333
|
-
-
|
|
334
|
-
-
|
|
335
|
-
-
|
|
336
|
-
-
|
|
337
|
-
-
|
|
338
|
-
-
|
|
339
|
-
-
|
|
333
|
+
- Components are functions that return UI
|
|
334
|
+
- How to create a component
|
|
335
|
+
- PascalCase naming convention
|
|
336
|
+
- Passing data to components with props
|
|
337
|
+
- Receiving props as a single object
|
|
338
|
+
- Composing components (nesting)
|
|
339
|
+
- Organizing app into multiple components
|
|
340
340
|
|
|
341
341
|
---
|
|
342
342
|
|
|
343
|
-
##
|
|
343
|
+
## Common Issues
|
|
344
344
|
|
|
345
345
|
### Issue: Component not showing up
|
|
346
346
|
|
|
@@ -354,12 +354,12 @@ let myText = "Learn Jac";
|
|
|
354
354
|
**Cause**: Using individual parameters instead of props object
|
|
355
355
|
|
|
356
356
|
```jac
|
|
357
|
-
#
|
|
357
|
+
# Wrong
|
|
358
358
|
def TodoItem(text: str, done: bool) -> any {
|
|
359
359
|
# ...
|
|
360
360
|
}
|
|
361
361
|
|
|
362
|
-
#
|
|
362
|
+
# Correct
|
|
363
363
|
def TodoItem(props: any) -> any {
|
|
364
364
|
let text = props.text;
|
|
365
365
|
# ...
|
|
@@ -385,7 +385,7 @@ def TodoItem(props: any) -> any {
|
|
|
385
385
|
|
|
386
386
|
---
|
|
387
387
|
|
|
388
|
-
##
|
|
388
|
+
## Quick Exercise
|
|
389
389
|
|
|
390
390
|
Try adding a new component:
|
|
391
391
|
|
|
@@ -409,8 +409,8 @@ def app() -> any {
|
|
|
409
409
|
|
|
410
410
|
---
|
|
411
411
|
|
|
412
|
-
##
|
|
412
|
+
## Next Step
|
|
413
413
|
|
|
414
414
|
Great! You can now create and organize components. But they look plain. Let's make them beautiful with **styling**!
|
|
415
415
|
|
|
416
|
-
|
|
416
|
+
**[Continue to Step 3: Styling](./step-03-styling.md)**
|