jac-client 0.2.3__py3-none-any.whl → 0.2.8__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 (224) hide show
  1. jac_client/examples/all-in-one/app.jac +494 -347
  2. jac_client/examples/all-in-one/assets/workers/worker.py +5 -0
  3. jac_client/examples/all-in-one/button.jac +1 -1
  4. jac_client/examples/all-in-one/components/CategoryFilter.jac +35 -0
  5. jac_client/examples/all-in-one/components/Header.jac +13 -0
  6. jac_client/examples/all-in-one/components/ProfitOverview.jac +50 -0
  7. jac_client/examples/all-in-one/components/Summary.jac +53 -0
  8. jac_client/examples/all-in-one/components/TransactionForm.jac +158 -0
  9. jac_client/examples/all-in-one/components/TransactionItem.jac +55 -0
  10. jac_client/examples/all-in-one/components/TransactionList.jac +37 -0
  11. jac_client/examples/all-in-one/components/button.jac +1 -1
  12. jac_client/examples/all-in-one/components/navigation.jac +132 -0
  13. jac_client/examples/all-in-one/constants/categories.jac +37 -0
  14. jac_client/examples/all-in-one/constants/clients.jac +13 -0
  15. jac_client/examples/all-in-one/context/BudgetContext.jac +28 -0
  16. jac_client/examples/all-in-one/hooks/useBudget.jac +116 -0
  17. jac_client/examples/all-in-one/hooks/useLocalStorage.jac +36 -0
  18. jac_client/examples/all-in-one/pages/BudgetPlanner.cl.jac +70 -0
  19. jac_client/examples/all-in-one/pages/BudgetPlanner.jac +126 -0
  20. jac_client/examples/all-in-one/pages/FeaturesTest.cl.jac +552 -0
  21. jac_client/examples/all-in-one/pages/FeaturesTest.jac +126 -0
  22. jac_client/examples/all-in-one/pages/LandingPage.jac +101 -0
  23. jac_client/examples/all-in-one/pages/loginPage.jac +132 -0
  24. jac_client/examples/all-in-one/pages/nestedDemo.jac +61 -0
  25. jac_client/examples/all-in-one/pages/notFound.jac +24 -0
  26. jac_client/examples/all-in-one/pages/signupPage.jac +133 -0
  27. jac_client/examples/all-in-one/utils/formatters.jac +52 -0
  28. jac_client/examples/asset-serving/css-with-image/{app.jac → src/app.jac} +4 -4
  29. jac_client/examples/asset-serving/image-asset/{app.jac → src/app.jac} +4 -4
  30. jac_client/examples/asset-serving/import-alias/{app.jac → src/app.jac} +5 -5
  31. jac_client/examples/basic/{app.jac → src/app.jac} +4 -4
  32. jac_client/examples/basic-auth/src/app.jac +371 -0
  33. jac_client/examples/basic-auth-with-router/{app.jac → src/app.jac} +28 -28
  34. jac_client/examples/basic-full-stack/{app.jac → src/app.jac} +166 -127
  35. jac_client/examples/css-styling/js-styling/{app.jac → src/app.jac} +7 -7
  36. jac_client/examples/css-styling/material-ui/{app.jac → src/app.jac} +6 -6
  37. jac_client/examples/css-styling/pure-css/{app.jac → src/app.jac} +7 -7
  38. jac_client/examples/css-styling/sass-example/{app.jac → src/app.jac} +7 -7
  39. jac_client/examples/css-styling/styled-components/{app.jac → src/app.jac} +6 -6
  40. jac_client/examples/css-styling/tailwind-example/{app.jac → src/app.jac} +7 -7
  41. jac_client/examples/full-stack-with-auth/{app.jac → src/app.jac} +47 -47
  42. jac_client/examples/little-x/{app.jac → src/app.jac} +27 -32
  43. jac_client/examples/little-x/src/submit-button.jac +16 -0
  44. jac_client/examples/nested-folders/nested-advance/{ButtonRoot.jac → src/ButtonRoot.jac} +1 -1
  45. jac_client/examples/nested-folders/nested-advance/{app.jac → src/app.jac} +1 -1
  46. jac_client/examples/nested-folders/nested-advance/{level1 → src/level1}/ButtonSecondL.jac +1 -1
  47. jac_client/examples/nested-folders/nested-advance/{level1 → src/level1}/Card.jac +1 -1
  48. jac_client/examples/nested-folders/nested-advance/{level1 → src/level1}/level2/ButtonThirdL.jac +1 -1
  49. jac_client/examples/nested-folders/nested-basic/{app.jac → src/app.jac} +2 -2
  50. jac_client/examples/nested-folders/nested-basic/{button.jac → src/button.jac} +1 -1
  51. jac_client/examples/nested-folders/nested-basic/{components → src/components}/button.jac +1 -1
  52. jac_client/examples/ts-support/src/app.jac +35 -0
  53. jac_client/examples/with-router/{app.jac → src/app.jac} +15 -15
  54. jac_client/plugin/cli.jac +504 -0
  55. jac_client/plugin/client.jac +45 -0
  56. jac_client/plugin/client_runtime.cl.jac +42 -0
  57. jac_client/plugin/impl/client.impl.jac +193 -0
  58. jac_client/plugin/impl/client_runtime.impl.jac +195 -0
  59. jac_client/plugin/impl/vite_client_bundle.impl.jac +72 -0
  60. jac_client/plugin/plugin_config.jac +195 -0
  61. jac_client/plugin/src/__init__.jac +20 -0
  62. jac_client/plugin/src/asset_processor.jac +33 -0
  63. jac_client/plugin/src/babel_processor.jac +18 -0
  64. jac_client/plugin/src/compiler.jac +67 -0
  65. jac_client/plugin/src/config_loader.jac +32 -0
  66. jac_client/plugin/src/impl/asset_processor.impl.jac +127 -0
  67. jac_client/plugin/src/impl/babel_processor.impl.jac +89 -0
  68. jac_client/plugin/src/impl/compiler.impl.jac +288 -0
  69. jac_client/plugin/src/impl/config_loader.impl.jac +119 -0
  70. jac_client/plugin/src/impl/import_processor.impl.jac +33 -0
  71. jac_client/plugin/src/impl/jac_to_js.impl.jac +41 -0
  72. jac_client/plugin/src/impl/package_installer.impl.jac +105 -0
  73. jac_client/plugin/src/impl/vite_bundler.impl.jac +626 -0
  74. jac_client/plugin/src/import_processor.jac +19 -0
  75. jac_client/plugin/src/jac_to_js.jac +35 -0
  76. jac_client/plugin/src/package_installer.jac +26 -0
  77. jac_client/plugin/src/vite_bundler.jac +44 -0
  78. jac_client/plugin/vite_client_bundle.jac +31 -0
  79. jac_client/tests/conftest.py +283 -0
  80. jac_client/tests/fixtures/basic-app/app.jac +2 -2
  81. jac_client/tests/fixtures/cl_file/app.cl.jac +2 -2
  82. jac_client/tests/fixtures/client_app_with_antd/app.jac +1 -1
  83. jac_client/tests/fixtures/js_import/app.jac +5 -5
  84. jac_client/tests/fixtures/spawn_test/app.jac +15 -18
  85. jac_client/tests/fixtures/with-ts/app.jac +35 -0
  86. jac_client/tests/test_cli.py +811 -0
  87. jac_client/tests/test_it.py +592 -97
  88. {jac_client-0.2.3.dist-info → jac_client-0.2.8.dist-info}/METADATA +41 -34
  89. jac_client-0.2.8.dist-info/RECORD +97 -0
  90. {jac_client-0.2.3.dist-info → jac_client-0.2.8.dist-info}/WHEEL +2 -1
  91. jac_client-0.2.8.dist-info/entry_points.txt +4 -0
  92. jac_client-0.2.8.dist-info/top_level.txt +1 -0
  93. jac_client/docs/README.md +0 -689
  94. jac_client/docs/advanced-state.md +0 -1265
  95. jac_client/docs/asset-serving/intro.md +0 -209
  96. jac_client/docs/assets/pipe_line-v2.svg +0 -32
  97. jac_client/docs/assets/pipe_line.png +0 -0
  98. jac_client/docs/file-system/app.jac.md +0 -121
  99. jac_client/docs/file-system/backend-frontend.md +0 -217
  100. jac_client/docs/file-system/intro.md +0 -72
  101. jac_client/docs/file-system/nested-imports.md +0 -348
  102. jac_client/docs/guide-example/intro.md +0 -115
  103. jac_client/docs/guide-example/step-01-setup.md +0 -270
  104. jac_client/docs/guide-example/step-02-components.md +0 -416
  105. jac_client/docs/guide-example/step-03-styling.md +0 -478
  106. jac_client/docs/guide-example/step-04-todo-ui.md +0 -477
  107. jac_client/docs/guide-example/step-05-local-state.md +0 -530
  108. jac_client/docs/guide-example/step-06-events.md +0 -749
  109. jac_client/docs/guide-example/step-07-effects.md +0 -468
  110. jac_client/docs/guide-example/step-08-walkers.md +0 -534
  111. jac_client/docs/guide-example/step-09-authentication.md +0 -586
  112. jac_client/docs/guide-example/step-10-routing.md +0 -539
  113. jac_client/docs/guide-example/step-11-final.md +0 -963
  114. jac_client/docs/imports.md +0 -1141
  115. jac_client/docs/lifecycle-hooks.md +0 -773
  116. jac_client/docs/routing.md +0 -659
  117. jac_client/docs/styling/intro.md +0 -249
  118. jac_client/docs/styling/js-styling.md +0 -367
  119. jac_client/docs/styling/material-ui.md +0 -341
  120. jac_client/docs/styling/pure-css.md +0 -299
  121. jac_client/docs/styling/sass.md +0 -403
  122. jac_client/docs/styling/styled-components.md +0 -395
  123. jac_client/docs/styling/tailwind.md +0 -298
  124. jac_client/examples/all-in-one/.babelrc +0 -9
  125. jac_client/examples/all-in-one/README.md +0 -16
  126. jac_client/examples/all-in-one/assets/burger.png +0 -0
  127. jac_client/examples/all-in-one/package.json +0 -29
  128. jac_client/examples/all-in-one/styles.css +0 -26
  129. jac_client/examples/all-in-one/vite.config.js +0 -28
  130. jac_client/examples/asset-serving/css-with-image/.babelrc +0 -9
  131. jac_client/examples/asset-serving/css-with-image/README.md +0 -91
  132. jac_client/examples/asset-serving/css-with-image/assets/burger.png +0 -0
  133. jac_client/examples/asset-serving/css-with-image/package.json +0 -28
  134. jac_client/examples/asset-serving/css-with-image/styles.css +0 -26
  135. jac_client/examples/asset-serving/css-with-image/vite.config.js +0 -28
  136. jac_client/examples/asset-serving/image-asset/.babelrc +0 -9
  137. jac_client/examples/asset-serving/image-asset/README.md +0 -119
  138. jac_client/examples/asset-serving/image-asset/assets/burger.png +0 -0
  139. jac_client/examples/asset-serving/image-asset/package.json +0 -28
  140. jac_client/examples/asset-serving/image-asset/styles.css +0 -26
  141. jac_client/examples/asset-serving/image-asset/vite.config.js +0 -28
  142. jac_client/examples/asset-serving/import-alias/.babelrc +0 -9
  143. jac_client/examples/asset-serving/import-alias/README.md +0 -83
  144. jac_client/examples/asset-serving/import-alias/assets/burger.png +0 -0
  145. jac_client/examples/asset-serving/import-alias/package.json +0 -28
  146. jac_client/examples/asset-serving/import-alias/vite.config.js +0 -28
  147. jac_client/examples/basic/.babelrc +0 -9
  148. jac_client/examples/basic/README.md +0 -16
  149. jac_client/examples/basic/package.json +0 -27
  150. jac_client/examples/basic/vite.config.js +0 -27
  151. jac_client/examples/basic-auth/.babelrc +0 -9
  152. jac_client/examples/basic-auth/README.md +0 -16
  153. jac_client/examples/basic-auth/app.jac +0 -308
  154. jac_client/examples/basic-auth/package.json +0 -27
  155. jac_client/examples/basic-auth/vite.config.js +0 -27
  156. jac_client/examples/basic-auth-with-router/.babelrc +0 -9
  157. jac_client/examples/basic-auth-with-router/README.md +0 -60
  158. jac_client/examples/basic-auth-with-router/package.json +0 -28
  159. jac_client/examples/basic-auth-with-router/vite.config.js +0 -27
  160. jac_client/examples/basic-full-stack/.babelrc +0 -9
  161. jac_client/examples/basic-full-stack/README.md +0 -18
  162. jac_client/examples/basic-full-stack/package.json +0 -28
  163. jac_client/examples/basic-full-stack/vite.config.js +0 -27
  164. jac_client/examples/css-styling/js-styling/.babelrc +0 -9
  165. jac_client/examples/css-styling/js-styling/README.md +0 -183
  166. jac_client/examples/css-styling/js-styling/package.json +0 -28
  167. jac_client/examples/css-styling/js-styling/styles.js +0 -100
  168. jac_client/examples/css-styling/js-styling/vite.config.js +0 -27
  169. jac_client/examples/css-styling/material-ui/.babelrc +0 -9
  170. jac_client/examples/css-styling/material-ui/README.md +0 -16
  171. jac_client/examples/css-styling/material-ui/package.json +0 -32
  172. jac_client/examples/css-styling/material-ui/vite.config.js +0 -27
  173. jac_client/examples/css-styling/pure-css/.babelrc +0 -9
  174. jac_client/examples/css-styling/pure-css/README.md +0 -16
  175. jac_client/examples/css-styling/pure-css/package.json +0 -28
  176. jac_client/examples/css-styling/pure-css/styles.css +0 -111
  177. jac_client/examples/css-styling/pure-css/vite.config.js +0 -27
  178. jac_client/examples/css-styling/sass-example/.babelrc +0 -9
  179. jac_client/examples/css-styling/sass-example/README.md +0 -16
  180. jac_client/examples/css-styling/sass-example/package.json +0 -29
  181. jac_client/examples/css-styling/sass-example/styles.scss +0 -153
  182. jac_client/examples/css-styling/sass-example/vite.config.js +0 -27
  183. jac_client/examples/css-styling/styled-components/.babelrc +0 -9
  184. jac_client/examples/css-styling/styled-components/README.md +0 -16
  185. jac_client/examples/css-styling/styled-components/package.json +0 -29
  186. jac_client/examples/css-styling/styled-components/styled.js +0 -90
  187. jac_client/examples/css-styling/styled-components/vite.config.js +0 -27
  188. jac_client/examples/css-styling/tailwind-example/.babelrc +0 -9
  189. jac_client/examples/css-styling/tailwind-example/README.md +0 -16
  190. jac_client/examples/css-styling/tailwind-example/global.css +0 -1
  191. jac_client/examples/css-styling/tailwind-example/package.json +0 -30
  192. jac_client/examples/css-styling/tailwind-example/vite.config.js +0 -29
  193. jac_client/examples/full-stack-with-auth/.babelrc +0 -9
  194. jac_client/examples/full-stack-with-auth/README.md +0 -16
  195. jac_client/examples/full-stack-with-auth/package.json +0 -28
  196. jac_client/examples/full-stack-with-auth/vite.config.js +0 -29
  197. jac_client/examples/little-x/package.json +0 -23
  198. jac_client/examples/little-x/submit-button.jac +0 -8
  199. jac_client/examples/nested-folders/nested-advance/.babelrc +0 -9
  200. jac_client/examples/nested-folders/nested-advance/README.md +0 -77
  201. jac_client/examples/nested-folders/nested-advance/package.json +0 -29
  202. jac_client/examples/nested-folders/nested-advance/vite.config.js +0 -28
  203. jac_client/examples/nested-folders/nested-basic/.babelrc +0 -9
  204. jac_client/examples/nested-folders/nested-basic/README.md +0 -183
  205. jac_client/examples/nested-folders/nested-basic/app.js +0 -7
  206. jac_client/examples/nested-folders/nested-basic/package.json +0 -28
  207. jac_client/examples/nested-folders/nested-basic/vite.config.js +0 -27
  208. jac_client/examples/with-router/.babelrc +0 -9
  209. jac_client/examples/with-router/README.md +0 -17
  210. jac_client/examples/with-router/package.json +0 -28
  211. jac_client/examples/with-router/vite.config.js +0 -27
  212. jac_client/plugin/cli.py +0 -244
  213. jac_client/plugin/client.py +0 -152
  214. jac_client/plugin/client_runtime.jac +0 -234
  215. jac_client/plugin/vite_client_bundle.py +0 -503
  216. jac_client/tests/fixtures/js_import/utils.js +0 -21
  217. jac_client/tests/fixtures/package-lock.json +0 -329
  218. jac_client/tests/fixtures/package.json +0 -11
  219. jac_client/tests/test_asset_examples.py +0 -322
  220. jac_client/tests/test_cl.py +0 -530
  221. jac_client/tests/test_create_jac_app.py +0 -131
  222. jac_client/tests/test_nested_file.py +0 -374
  223. jac_client-0.2.3.dist-info/RECORD +0 -171
  224. 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
- }