jac-client 0.2.3__py3-none-any.whl → 0.2.6__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.
Files changed (202) hide show
  1. jac_client/examples/all-in-one/assets/workers/worker.py +5 -0
  2. jac_client/examples/all-in-one/src/app.jac +841 -0
  3. jac_client/examples/all-in-one/{button.jac → src/button.jac} +1 -1
  4. jac_client/examples/all-in-one/{components → src/components}/button.jac +1 -1
  5. jac_client/examples/asset-serving/css-with-image/{app.jac → src/app.jac} +2 -2
  6. jac_client/examples/asset-serving/image-asset/{app.jac → src/app.jac} +2 -2
  7. jac_client/examples/asset-serving/import-alias/{app.jac → src/app.jac} +3 -3
  8. jac_client/examples/basic/{app.jac → src/app.jac} +2 -2
  9. jac_client/examples/basic-auth/src/app.jac +377 -0
  10. jac_client/examples/basic-auth-with-router/{app.jac → src/app.jac} +18 -18
  11. jac_client/examples/basic-full-stack/{app.jac → src/app.jac} +175 -130
  12. jac_client/examples/css-styling/js-styling/{app.jac → src/app.jac} +6 -6
  13. jac_client/examples/css-styling/material-ui/{app.jac → src/app.jac} +5 -5
  14. jac_client/examples/css-styling/pure-css/{app.jac → src/app.jac} +6 -6
  15. jac_client/examples/css-styling/sass-example/{app.jac → src/app.jac} +6 -6
  16. jac_client/examples/css-styling/styled-components/{app.jac → src/app.jac} +5 -5
  17. jac_client/examples/css-styling/tailwind-example/{app.jac → src/app.jac} +6 -6
  18. jac_client/examples/full-stack-with-auth/{app.jac → src/app.jac} +37 -37
  19. jac_client/examples/little-x/{app.jac → src/app.jac} +27 -32
  20. jac_client/examples/little-x/src/submit-button.jac +16 -0
  21. jac_client/examples/nested-folders/nested-advance/{ButtonRoot.jac → src/ButtonRoot.jac} +1 -1
  22. jac_client/examples/nested-folders/nested-advance/{app.jac → src/app.jac} +1 -1
  23. jac_client/examples/nested-folders/nested-advance/{level1 → src/level1}/ButtonSecondL.jac +1 -1
  24. jac_client/examples/nested-folders/nested-advance/{level1 → src/level1}/Card.jac +1 -1
  25. jac_client/examples/nested-folders/nested-advance/{level1 → src/level1}/level2/ButtonThirdL.jac +1 -1
  26. jac_client/examples/nested-folders/nested-basic/{app.jac → src/app.jac} +2 -2
  27. jac_client/examples/nested-folders/nested-basic/{button.jac → src/button.jac} +1 -1
  28. jac_client/examples/nested-folders/nested-basic/{components → src/components}/button.jac +1 -1
  29. jac_client/examples/ts-support/src/app.jac +35 -0
  30. jac_client/examples/with-router/{app.jac → src/app.jac} +11 -11
  31. jac_client/plugin/cli.jac +547 -0
  32. jac_client/plugin/client.jac +52 -0
  33. jac_client/plugin/client_runtime.cl.jac +38 -0
  34. jac_client/plugin/impl/client.impl.jac +134 -0
  35. jac_client/plugin/impl/client_runtime.impl.jac +177 -0
  36. jac_client/plugin/impl/vite_client_bundle.impl.jac +72 -0
  37. jac_client/plugin/plugin_config.jac +195 -0
  38. jac_client/plugin/src/__init__.jac +20 -0
  39. jac_client/plugin/src/asset_processor.jac +33 -0
  40. jac_client/plugin/src/babel_processor.jac +18 -0
  41. jac_client/plugin/src/compiler.jac +66 -0
  42. jac_client/plugin/src/config_loader.jac +32 -0
  43. jac_client/plugin/src/impl/asset_processor.impl.jac +127 -0
  44. jac_client/plugin/src/impl/babel_processor.impl.jac +84 -0
  45. jac_client/plugin/src/impl/compiler.impl.jac +251 -0
  46. jac_client/plugin/src/impl/config_loader.impl.jac +119 -0
  47. jac_client/plugin/src/impl/import_processor.impl.jac +33 -0
  48. jac_client/plugin/src/impl/jac_to_js.impl.jac +41 -0
  49. jac_client/plugin/src/impl/package_installer.impl.jac +105 -0
  50. jac_client/plugin/src/impl/vite_bundler.impl.jac +513 -0
  51. jac_client/plugin/src/import_processor.jac +19 -0
  52. jac_client/plugin/src/jac_to_js.jac +35 -0
  53. jac_client/plugin/src/package_installer.jac +26 -0
  54. jac_client/plugin/src/vite_bundler.jac +36 -0
  55. jac_client/plugin/vite_client_bundle.jac +31 -0
  56. jac_client/tests/conftest.py +281 -0
  57. jac_client/tests/fixtures/basic-app/app.jac +2 -2
  58. jac_client/tests/fixtures/cl_file/app.cl.jac +2 -2
  59. jac_client/tests/fixtures/client_app_with_antd/app.jac +1 -1
  60. jac_client/tests/fixtures/js_import/app.jac +5 -5
  61. jac_client/tests/fixtures/spawn_test/app.jac +7 -7
  62. jac_client/tests/fixtures/with-ts/app.jac +35 -0
  63. jac_client/tests/test_cli.py +755 -0
  64. jac_client/tests/test_it.py +347 -67
  65. {jac_client-0.2.3.dist-info → jac_client-0.2.6.dist-info}/METADATA +28 -30
  66. jac_client-0.2.6.dist-info/RECORD +74 -0
  67. {jac_client-0.2.3.dist-info → jac_client-0.2.6.dist-info}/WHEEL +2 -1
  68. jac_client-0.2.6.dist-info/entry_points.txt +4 -0
  69. jac_client-0.2.6.dist-info/top_level.txt +1 -0
  70. jac_client/docs/README.md +0 -689
  71. jac_client/docs/advanced-state.md +0 -1265
  72. jac_client/docs/asset-serving/intro.md +0 -209
  73. jac_client/docs/assets/pipe_line-v2.svg +0 -32
  74. jac_client/docs/assets/pipe_line.png +0 -0
  75. jac_client/docs/file-system/app.jac.md +0 -121
  76. jac_client/docs/file-system/backend-frontend.md +0 -217
  77. jac_client/docs/file-system/intro.md +0 -72
  78. jac_client/docs/file-system/nested-imports.md +0 -348
  79. jac_client/docs/guide-example/intro.md +0 -115
  80. jac_client/docs/guide-example/step-01-setup.md +0 -270
  81. jac_client/docs/guide-example/step-02-components.md +0 -416
  82. jac_client/docs/guide-example/step-03-styling.md +0 -478
  83. jac_client/docs/guide-example/step-04-todo-ui.md +0 -477
  84. jac_client/docs/guide-example/step-05-local-state.md +0 -530
  85. jac_client/docs/guide-example/step-06-events.md +0 -749
  86. jac_client/docs/guide-example/step-07-effects.md +0 -468
  87. jac_client/docs/guide-example/step-08-walkers.md +0 -534
  88. jac_client/docs/guide-example/step-09-authentication.md +0 -586
  89. jac_client/docs/guide-example/step-10-routing.md +0 -539
  90. jac_client/docs/guide-example/step-11-final.md +0 -963
  91. jac_client/docs/imports.md +0 -1141
  92. jac_client/docs/lifecycle-hooks.md +0 -773
  93. jac_client/docs/routing.md +0 -659
  94. jac_client/docs/styling/intro.md +0 -249
  95. jac_client/docs/styling/js-styling.md +0 -367
  96. jac_client/docs/styling/material-ui.md +0 -341
  97. jac_client/docs/styling/pure-css.md +0 -299
  98. jac_client/docs/styling/sass.md +0 -403
  99. jac_client/docs/styling/styled-components.md +0 -395
  100. jac_client/docs/styling/tailwind.md +0 -298
  101. jac_client/examples/all-in-one/.babelrc +0 -9
  102. jac_client/examples/all-in-one/README.md +0 -16
  103. jac_client/examples/all-in-one/app.jac +0 -426
  104. jac_client/examples/all-in-one/assets/burger.png +0 -0
  105. jac_client/examples/all-in-one/package.json +0 -29
  106. jac_client/examples/all-in-one/styles.css +0 -26
  107. jac_client/examples/all-in-one/vite.config.js +0 -28
  108. jac_client/examples/asset-serving/css-with-image/.babelrc +0 -9
  109. jac_client/examples/asset-serving/css-with-image/README.md +0 -91
  110. jac_client/examples/asset-serving/css-with-image/assets/burger.png +0 -0
  111. jac_client/examples/asset-serving/css-with-image/package.json +0 -28
  112. jac_client/examples/asset-serving/css-with-image/styles.css +0 -26
  113. jac_client/examples/asset-serving/css-with-image/vite.config.js +0 -28
  114. jac_client/examples/asset-serving/image-asset/.babelrc +0 -9
  115. jac_client/examples/asset-serving/image-asset/README.md +0 -119
  116. jac_client/examples/asset-serving/image-asset/assets/burger.png +0 -0
  117. jac_client/examples/asset-serving/image-asset/package.json +0 -28
  118. jac_client/examples/asset-serving/image-asset/styles.css +0 -26
  119. jac_client/examples/asset-serving/image-asset/vite.config.js +0 -28
  120. jac_client/examples/asset-serving/import-alias/.babelrc +0 -9
  121. jac_client/examples/asset-serving/import-alias/README.md +0 -83
  122. jac_client/examples/asset-serving/import-alias/assets/burger.png +0 -0
  123. jac_client/examples/asset-serving/import-alias/package.json +0 -28
  124. jac_client/examples/asset-serving/import-alias/vite.config.js +0 -28
  125. jac_client/examples/basic/.babelrc +0 -9
  126. jac_client/examples/basic/README.md +0 -16
  127. jac_client/examples/basic/package.json +0 -27
  128. jac_client/examples/basic/vite.config.js +0 -27
  129. jac_client/examples/basic-auth/.babelrc +0 -9
  130. jac_client/examples/basic-auth/README.md +0 -16
  131. jac_client/examples/basic-auth/app.jac +0 -308
  132. jac_client/examples/basic-auth/package.json +0 -27
  133. jac_client/examples/basic-auth/vite.config.js +0 -27
  134. jac_client/examples/basic-auth-with-router/.babelrc +0 -9
  135. jac_client/examples/basic-auth-with-router/README.md +0 -60
  136. jac_client/examples/basic-auth-with-router/package.json +0 -28
  137. jac_client/examples/basic-auth-with-router/vite.config.js +0 -27
  138. jac_client/examples/basic-full-stack/.babelrc +0 -9
  139. jac_client/examples/basic-full-stack/README.md +0 -18
  140. jac_client/examples/basic-full-stack/package.json +0 -28
  141. jac_client/examples/basic-full-stack/vite.config.js +0 -27
  142. jac_client/examples/css-styling/js-styling/.babelrc +0 -9
  143. jac_client/examples/css-styling/js-styling/README.md +0 -183
  144. jac_client/examples/css-styling/js-styling/package.json +0 -28
  145. jac_client/examples/css-styling/js-styling/styles.js +0 -100
  146. jac_client/examples/css-styling/js-styling/vite.config.js +0 -27
  147. jac_client/examples/css-styling/material-ui/.babelrc +0 -9
  148. jac_client/examples/css-styling/material-ui/README.md +0 -16
  149. jac_client/examples/css-styling/material-ui/package.json +0 -32
  150. jac_client/examples/css-styling/material-ui/vite.config.js +0 -27
  151. jac_client/examples/css-styling/pure-css/.babelrc +0 -9
  152. jac_client/examples/css-styling/pure-css/README.md +0 -16
  153. jac_client/examples/css-styling/pure-css/package.json +0 -28
  154. jac_client/examples/css-styling/pure-css/styles.css +0 -111
  155. jac_client/examples/css-styling/pure-css/vite.config.js +0 -27
  156. jac_client/examples/css-styling/sass-example/.babelrc +0 -9
  157. jac_client/examples/css-styling/sass-example/README.md +0 -16
  158. jac_client/examples/css-styling/sass-example/package.json +0 -29
  159. jac_client/examples/css-styling/sass-example/styles.scss +0 -153
  160. jac_client/examples/css-styling/sass-example/vite.config.js +0 -27
  161. jac_client/examples/css-styling/styled-components/.babelrc +0 -9
  162. jac_client/examples/css-styling/styled-components/README.md +0 -16
  163. jac_client/examples/css-styling/styled-components/package.json +0 -29
  164. jac_client/examples/css-styling/styled-components/styled.js +0 -90
  165. jac_client/examples/css-styling/styled-components/vite.config.js +0 -27
  166. jac_client/examples/css-styling/tailwind-example/.babelrc +0 -9
  167. jac_client/examples/css-styling/tailwind-example/README.md +0 -16
  168. jac_client/examples/css-styling/tailwind-example/global.css +0 -1
  169. jac_client/examples/css-styling/tailwind-example/package.json +0 -30
  170. jac_client/examples/css-styling/tailwind-example/vite.config.js +0 -29
  171. jac_client/examples/full-stack-with-auth/.babelrc +0 -9
  172. jac_client/examples/full-stack-with-auth/README.md +0 -16
  173. jac_client/examples/full-stack-with-auth/package.json +0 -28
  174. jac_client/examples/full-stack-with-auth/vite.config.js +0 -29
  175. jac_client/examples/little-x/package.json +0 -23
  176. jac_client/examples/little-x/submit-button.jac +0 -8
  177. jac_client/examples/nested-folders/nested-advance/.babelrc +0 -9
  178. jac_client/examples/nested-folders/nested-advance/README.md +0 -77
  179. jac_client/examples/nested-folders/nested-advance/package.json +0 -29
  180. jac_client/examples/nested-folders/nested-advance/vite.config.js +0 -28
  181. jac_client/examples/nested-folders/nested-basic/.babelrc +0 -9
  182. jac_client/examples/nested-folders/nested-basic/README.md +0 -183
  183. jac_client/examples/nested-folders/nested-basic/app.js +0 -7
  184. jac_client/examples/nested-folders/nested-basic/package.json +0 -28
  185. jac_client/examples/nested-folders/nested-basic/vite.config.js +0 -27
  186. jac_client/examples/with-router/.babelrc +0 -9
  187. jac_client/examples/with-router/README.md +0 -17
  188. jac_client/examples/with-router/package.json +0 -28
  189. jac_client/examples/with-router/vite.config.js +0 -27
  190. jac_client/plugin/cli.py +0 -244
  191. jac_client/plugin/client.py +0 -152
  192. jac_client/plugin/client_runtime.jac +0 -234
  193. jac_client/plugin/vite_client_bundle.py +0 -503
  194. jac_client/tests/fixtures/js_import/utils.js +0 -21
  195. jac_client/tests/fixtures/package-lock.json +0 -329
  196. jac_client/tests/fixtures/package.json +0 -11
  197. jac_client/tests/test_asset_examples.py +0 -322
  198. jac_client/tests/test_cl.py +0 -530
  199. jac_client/tests/test_create_jac_app.py +0 -131
  200. jac_client/tests/test_nested_file.py +0 -374
  201. jac_client-0.2.3.dist-info/RECORD +0 -171
  202. jac_client-0.2.3.dist-info/entry_points.txt +0 -4
@@ -1,503 +0,0 @@
1
- """Vite-enhanced client bundle generation for Jac web front-ends."""
2
-
3
- from __future__ import annotations
4
-
5
- import contextlib
6
- import hashlib
7
- import shutil
8
- import subprocess
9
- from pathlib import Path
10
- from types import ModuleType
11
- from typing import TYPE_CHECKING, Any
12
-
13
- from jaclang.runtimelib.client_bundle import (
14
- ClientBundle,
15
- ClientBundleBuilder,
16
- ClientBundleError,
17
- )
18
-
19
- if TYPE_CHECKING:
20
- from jaclang.compiler.codeinfo import ClientManifest
21
-
22
-
23
- class ViteClientBundleBuilder(ClientBundleBuilder):
24
- """Enhanced ClientBundleBuilder that uses Vite for optimized bundling."""
25
-
26
- def __init__(
27
- self,
28
- runtime_path: Path | None = None,
29
- vite_output_dir: Path | None = None,
30
- vite_package_json: Path | None = None,
31
- vite_minify: bool = False,
32
- ) -> None:
33
- """Initialize the Vite-enhanced bundle builder.
34
-
35
- Args:
36
- runtime_path: Path to client runtime file
37
- vite_output_dir: Output directory for Vite builds (defaults to temp/dist)
38
- vite_package_json: Path to package.json for Vite (required)
39
- vite_minify: Whether to enable minification in Vite build
40
- """
41
- super().__init__(runtime_path)
42
- self.vite_output_dir = vite_output_dir
43
- self.vite_package_json = vite_package_json
44
- self.vite_minify = vite_minify
45
-
46
- def _process_vite_imports(
47
- self, manifest: ClientManifest | None, module_path: Path
48
- ) -> list[Path | None]:
49
- """Process client imports for Vite bundling.
50
-
51
- Only mark modules as bundled when we actually inline their code (.jac files we compile
52
- and local .js files we embed). Bare package specifiers (e.g., "antd") are left as real
53
- ES imports so Vite can resolve and bundle them.
54
- """
55
- imported_js_modules: list[Path | None] = []
56
- if manifest and manifest.imports:
57
- for _, import_path in manifest.imports.items():
58
- import_path_obj = Path(import_path)
59
-
60
- if import_path_obj.suffix == ".js":
61
- # Inline local JS files and mark as bundled
62
- try:
63
- imported_js_modules.append(import_path_obj)
64
- except FileNotFoundError:
65
- imported_js_modules.append(None)
66
-
67
- elif import_path_obj.suffix == ".jac":
68
- # Compile .jac imports and include transitive .jac imports
69
- try:
70
- imported_js_modules.append(import_path_obj)
71
- except ClientBundleError:
72
- imported_js_modules.append(None)
73
-
74
- else:
75
- # Non .jac/.js entries (likely bare specifiers) should be handled by Vite.
76
- # Do not inline or mark as bundled so their import lines are preserved.
77
- pass
78
-
79
- return imported_js_modules
80
-
81
- def _compile_dependencies_recursively(
82
- self,
83
- module_path: Path,
84
- visited: set[Path] | None = None,
85
- collected_exports: set[str] | None = None,
86
- collected_globals: dict[str, Any] | None = None,
87
- source_root: Path | None = None,
88
- ) -> None:
89
- """Recursively compile/copy .jac/.js imports to temp, skipping bundling.
90
-
91
- Only prepares dependency JS artifacts for Vite by writing compiled JS (.jac)
92
- or copying local JS (.js) into the temp directory. Bare specifiers are left
93
- untouched for Vite to resolve.
94
-
95
- Args:
96
- module_path: Path to the module being compiled
97
- visited: Set of already visited paths to avoid cycles
98
- collected_exports: Set to accumulate exported symbols
99
- collected_globals: Dict to accumulate global values
100
- source_root: Root directory of the source files (for preserving folder structure)
101
- """
102
- if visited is None:
103
- visited = set()
104
- if collected_exports is None:
105
- collected_exports = set()
106
- if collected_globals is None:
107
- collected_globals = {}
108
-
109
- module_path = module_path.resolve()
110
- if module_path in visited:
111
- return
112
- visited.add(module_path)
113
-
114
- # Set source_root on first call (root module's parent directory)
115
- if source_root is None:
116
- source_root = module_path.parent.resolve()
117
-
118
- manifest = None
119
-
120
- # Compile current module to JS and append registration
121
- module_js, mod = self._compile_to_js(module_path)
122
- manifest = mod.gen.client_manifest if mod else None
123
-
124
- # Extract exports from manifest
125
- exports_list = self._extract_client_exports(manifest)
126
- collected_exports.update(exports_list)
127
-
128
- # Build globals map using manifest.globals_values only for non-root
129
- non_root_globals: dict[str, Any] = {}
130
- if manifest:
131
- for name in manifest.globals:
132
- non_root_globals[name] = manifest.globals_values.get(name)
133
- collected_globals.update(non_root_globals)
134
- export_block = (
135
- f"export {{ {', '.join(exports_list)} }};\n" if exports_list else ""
136
- )
137
-
138
- # inport jacJsx from client_runtime_utils.jac
139
- jac_jsx_path = 'import {__jacJsx, __jacSpawn} from "@jac-client/utils";'
140
-
141
- combined_js = f"{jac_jsx_path}\n{module_js}\n{export_block}"
142
- if self.vite_package_json is not None:
143
- # Preserve folder structure: calculate relative path from source_root
144
- try:
145
- relative_path = module_path.relative_to(source_root)
146
- # Change extension from .jac to .js
147
- output_path = (
148
- self.vite_package_json.parent
149
- / "src"
150
- / relative_path.with_suffix(".js")
151
- )
152
- except ValueError:
153
- # If file is outside source_root, fall back to just filename
154
- output_path = (
155
- self.vite_package_json.parent / "src" / f"{module_path.stem}.js"
156
- )
157
-
158
- # Ensure parent directories exist
159
- output_path.parent.mkdir(parents=True, exist_ok=True)
160
- output_path.write_text(combined_js, encoding="utf-8")
161
-
162
- if not manifest or not manifest.imports:
163
- return
164
-
165
- for _name, import_path in manifest.imports.items():
166
- path_obj = Path(import_path).resolve()
167
- # Avoid re-processing
168
- if path_obj in visited:
169
- continue
170
- if path_obj.suffix == ".jac":
171
- # Recurse into transitive deps
172
- self._compile_dependencies_recursively(
173
- path_obj,
174
- visited,
175
- collected_exports=collected_exports,
176
- collected_globals=collected_globals,
177
- source_root=source_root,
178
- )
179
- elif path_obj.suffix == ".js":
180
- try:
181
- js_code = path_obj.read_text(encoding="utf-8")
182
- if self.vite_package_json is not None:
183
- # Preserve folder structure for .js files too
184
- try:
185
- relative_path = path_obj.relative_to(source_root)
186
- output_path = (
187
- self.vite_package_json.parent / "src" / relative_path
188
- )
189
- except ValueError:
190
- # If file is outside source_root, fall back to just filename
191
- output_path = (
192
- self.vite_package_json.parent / "src" / path_obj.name
193
- )
194
-
195
- # Ensure parent directories exist
196
- output_path.parent.mkdir(parents=True, exist_ok=True)
197
- output_path.write_text(js_code, encoding="utf-8")
198
- except FileNotFoundError:
199
- pass
200
- else:
201
- # Bare specifiers or other assets handled by Vite
202
- if self.vite_package_json is not None and path_obj.is_file():
203
- # Preserve folder structure for other assets too
204
- try:
205
- relative_path = path_obj.relative_to(source_root)
206
- output_path = (
207
- self.vite_package_json.parent / "src" / relative_path
208
- )
209
- except ValueError:
210
- # If file is outside source_root, fall back to just filename
211
- output_path = (
212
- self.vite_package_json.parent / "src" / path_obj.name
213
- )
214
-
215
- # Ensure parent directories exist
216
- output_path.parent.mkdir(parents=True, exist_ok=True)
217
- output_path.write_text(
218
- path_obj.read_text(encoding="utf-8"), encoding="utf-8"
219
- )
220
- continue
221
-
222
- def _compile_bundle(
223
- self,
224
- module: ModuleType,
225
- module_path: Path,
226
- ) -> ClientBundle:
227
- """Override to use Vite bundling instead of simple concatenation."""
228
-
229
- # Check if package.json exists before proceeding
230
- if not self.vite_package_json or not self.vite_package_json.exists():
231
- raise ClientBundleError(
232
- "Vite package.json not found. Set vite_package_json when using ViteClientBundleBuilder"
233
- )
234
-
235
- # client_runtime for jac client utils
236
- runtime_utils_path = self.runtime_path.parent / "client_runtime.jac"
237
- runtimeutils_js, mod = self._compile_to_js(runtime_utils_path)
238
- runtimeutils_manifest = mod.gen.client_manifest if mod else None
239
- runtimeutils_exports_list = self._extract_client_exports(runtimeutils_manifest)
240
-
241
- # Add React Router exports that are variable declarations (not functions)
242
- # These need to be manually added since they're 'let' declarations, not 'def' functions
243
- router_exports = [
244
- "Router",
245
- "Routes",
246
- "Route",
247
- "Link",
248
- "Navigate",
249
- "useNavigate",
250
- "useLocation",
251
- "useParams",
252
- ]
253
-
254
- # Combine manifest exports with router exports
255
- all_exports = sorted(set(runtimeutils_exports_list + router_exports))
256
-
257
- export_block = (
258
- f"export {{ {', '.join(all_exports)} }};\n" if all_exports else ""
259
- )
260
-
261
- combined_runtime_utils_js = f"{runtimeutils_js}\n{export_block}"
262
- (self.vite_package_json.parent / "src" / "client_runtime.js").write_text(
263
- combined_runtime_utils_js, encoding="utf-8"
264
- )
265
-
266
- # Get manifest from JacProgram first to check for imports
267
- # Collect exports/globals across root and recursive deps
268
- module_js, mod = self._compile_to_js(module_path)
269
- module_manifest = mod.gen.client_manifest if mod else None
270
- collected_exports: set[str] = set(self._extract_client_exports(module_manifest))
271
-
272
- client_globals_map = self._extract_client_globals(module_manifest, module)
273
- collected_globals: dict[str, Any] = dict(client_globals_map)
274
- # Recursively prepare dependencies and accumulate symbols
275
- self._compile_dependencies_recursively(
276
- module_path,
277
- collected_exports=collected_exports,
278
- collected_globals=collected_globals,
279
- )
280
-
281
- # Copy assets from root assets/ folder to src/assets/ for @jac-client/assets alias
282
- project_dir = self.vite_package_json.parent
283
- root_assets_dir = project_dir / "assets"
284
- src_assets_dir = project_dir / "src" / "assets"
285
- if root_assets_dir.exists() and root_assets_dir.is_dir():
286
- self._copy_asset_files(root_assets_dir, src_assets_dir)
287
-
288
- client_exports = sorted(collected_exports)
289
- client_globals_map = collected_globals
290
-
291
- entry_file = self.vite_package_json.parent / "src" / "main.js"
292
-
293
- entry_content = """import React from "react";
294
- import { createRoot } from "react-dom/client";
295
- import { app as App } from "./app.js";
296
-
297
- const root = createRoot(document.getElementById("root"));
298
- root.render(<App />);
299
- """
300
- entry_file.write_text(entry_content, encoding="utf-8")
301
-
302
- bundle_code, bundle_hash = self._bundle_with_vite(
303
- module.__name__, client_exports
304
- )
305
-
306
- return ClientBundle(
307
- module_name=module.__name__,
308
- code=bundle_code,
309
- client_functions=client_exports,
310
- client_globals=list(client_globals_map.keys()),
311
- hash=bundle_hash,
312
- )
313
-
314
- def _bundle_with_vite(
315
- self, module_name: str, client_functions: list[str]
316
- ) -> tuple[str, str]:
317
- """Bundle JavaScript code using Vite for optimization.
318
-
319
- Args:
320
- module_name: Name of the module being bundled
321
- client_functions: List of client function names
322
-
323
- Returns:
324
- Tuple of (bundle_code, bundle_hash)
325
-
326
- Raises:
327
- ClientBundleError: If Vite bundling fails
328
- """
329
- if not self.vite_package_json or not self.vite_package_json.exists():
330
- raise ClientBundleError(
331
- "Vite package.json not found. Set vite_package_json when using ViteClientBundleBuilder"
332
- )
333
-
334
- # Create temp directory for Vite build
335
- project_dir = self.vite_package_json.parent
336
- src_dir = project_dir / "src"
337
- src_dir.mkdir(exist_ok=True)
338
-
339
- output_dir = self.vite_output_dir or src_dir / "dist" / "assets"
340
- output_dir.mkdir(parents=True, exist_ok=True)
341
-
342
- try:
343
- # Run Vite build from project directory
344
- # need to install packages you told in package.json inside here
345
- # first compile the code
346
- command = ["npm", "run", "compile"]
347
- subprocess.run(
348
- command, cwd=project_dir, check=True, capture_output=True, text=True
349
- )
350
- # Copy CSS and other asset files from src/ to build/ after Babel compilation
351
- # Babel only transpiles JS, so we need to manually copy assets
352
- self._copy_asset_files(project_dir / "src", project_dir / "build")
353
- # then build the code
354
- command = ["npm", "run", "build"]
355
- subprocess.run(
356
- command, cwd=project_dir, check=True, capture_output=True, text=True
357
- )
358
- except subprocess.CalledProcessError as e:
359
- raise ClientBundleError(f"Vite build failed: {e.stderr}") from e
360
- except FileNotFoundError:
361
- raise ClientBundleError(
362
- "npx or vite command not found. Ensure Node.js and npm are installed."
363
- ) from None
364
- # Find the generated bundle file
365
- bundle_file = self._find_vite_bundle(output_dir)
366
- if not bundle_file:
367
- raise ClientBundleError("Vite build completed but no bundle file found")
368
-
369
- # Read the bundled code
370
- bundle_code = bundle_file.read_text(encoding="utf-8")
371
- bundle_hash = hashlib.sha256(bundle_code.encode("utf-8")).hexdigest()
372
-
373
- return bundle_code, bundle_hash
374
-
375
- def _generate_vite_config(self, entry_file: Path, output_dir: Path) -> str:
376
- """Generate Vite configuration for bundling."""
377
- entry_name = entry_file.as_posix()
378
- output_dir_name = output_dir.as_posix()
379
- minify_setting = "true" if self.vite_minify else "false"
380
-
381
- return f"""
382
- import {{ defineConfig }} from 'vite';
383
- import {{ resolve }} from 'path';
384
-
385
- export default defineConfig({{
386
- build: {{
387
- outDir: '{output_dir_name}',
388
- emptyOutDir: true,
389
- rollupOptions: {{
390
- input: {{
391
- main: resolve(__dirname, '{entry_name}'),
392
- }},
393
- output: {{
394
- entryFileNames: 'client.[hash].js',
395
- format: 'iife',
396
- name: 'JacClient',
397
- }},
398
- }},
399
- minify: {minify_setting}, // Configurable minification
400
- }},
401
- resolve: {{
402
- }}
403
- }});
404
- """
405
-
406
- def _copy_asset_files(self, src_dir: Path, build_dir: Path) -> None:
407
- """Copy CSS and other asset files from src/ to build/ directory recursively.
408
-
409
- Babel only transpiles JavaScript files, so CSS and other assets need to be
410
- manually copied to the build directory for Vite to resolve them.
411
- This method recursively copies assets from subdirectories (e.g., src/assets/)
412
- while preserving the directory structure.
413
- """
414
- if not src_dir.exists():
415
- return
416
-
417
- # Ensure build directory exists
418
- build_dir.mkdir(parents=True, exist_ok=True)
419
-
420
- # Asset file extensions to copy
421
- asset_extensions = {
422
- ".css",
423
- ".scss",
424
- ".sass",
425
- ".less",
426
- ".svg",
427
- ".png",
428
- ".jpg",
429
- ".jpeg",
430
- ".gif",
431
- ".webp",
432
- ".ico",
433
- ".woff",
434
- ".woff2",
435
- ".ttf",
436
- ".eot",
437
- ".otf",
438
- ".mp4",
439
- ".webm",
440
- ".mp3",
441
- ".wav",
442
- }
443
-
444
- def copy_recursive(
445
- source: Path, destination: Path, base: Path | None = None
446
- ) -> None:
447
- """Recursively copy asset files from source to destination.
448
-
449
- Args:
450
- source: Source directory to copy from
451
- destination: Destination directory to copy to
452
- base: Base directory for calculating relative paths (defaults to source)
453
- """
454
- if not source.exists():
455
- return
456
-
457
- if base is None:
458
- base = source
459
-
460
- for item in source.iterdir():
461
- if item.is_file() and item.suffix.lower() in asset_extensions:
462
- # Preserve relative path structure from base
463
- relative_path = item.relative_to(base)
464
- dest_file = destination / relative_path
465
- dest_file.parent.mkdir(parents=True, exist_ok=True)
466
- with contextlib.suppress(OSError, shutil.Error):
467
- shutil.copy2(item, dest_file)
468
- elif item.is_dir():
469
- # Recursively process subdirectories
470
- copy_recursive(item, destination, base)
471
-
472
- # Copy files from src_dir root and recursively from subdirectories
473
- copy_recursive(src_dir, build_dir)
474
-
475
- def _find_vite_bundle(self, output_dir: Path) -> Path | None:
476
- """Find the generated Vite bundle file."""
477
- for file in output_dir.glob("client.*.js"):
478
- return file
479
- return None
480
-
481
- def _find_vite_css(self, output_dir: Path) -> Path | None:
482
- """Find the generated Vite CSS file."""
483
- # Vite typically outputs CSS as main.css or with a hash
484
- # Try main.css first (most common), then any .css file
485
- css_file = output_dir / "main.css"
486
- if css_file.exists():
487
- return css_file
488
- # Fallback: find any CSS file
489
- for file in output_dir.glob("*.css"):
490
- return file
491
- return None
492
-
493
- def cleanup_temp_dir(self) -> None:
494
- """Clean up the src directory and its contents."""
495
- if not self.vite_package_json or not self.vite_package_json.exists():
496
- return
497
-
498
- project_dir = self.vite_package_json.parent
499
- temp_dir = project_dir / "src"
500
-
501
- if temp_dir.exists():
502
- with contextlib.suppress(OSError, shutil.Error):
503
- shutil.rmtree(temp_dir)
@@ -1,21 +0,0 @@
1
- // JavaScript utility functions for testing JS imports in Jac
2
-
3
- export function formatMessage(name) {
4
- return `Hello, ${name}!`;
5
- }
6
-
7
- export function calculateSum(a, b) {
8
- return a + b;
9
- }
10
-
11
- export const JS_CONSTANT = "Imported from JavaScript";
12
-
13
- export class MessageFormatter {
14
- constructor(prefix) {
15
- this.prefix = prefix;
16
- }
17
-
18
- format(text) {
19
- return `${this.prefix}: ${text}`;
20
- }
21
- }