jac-client 0.2.5__py3-none-any.whl → 0.2.7__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 (61) hide show
  1. jac_client/examples/all-in-one/src/app.jac +473 -741
  2. jac_client/examples/all-in-one/src/components/CategoryFilter.jac +35 -0
  3. jac_client/examples/all-in-one/src/components/Header.jac +13 -0
  4. jac_client/examples/all-in-one/src/components/ProfitOverview.jac +50 -0
  5. jac_client/examples/all-in-one/src/components/Summary.jac +53 -0
  6. jac_client/examples/all-in-one/src/components/TransactionForm.jac +158 -0
  7. jac_client/examples/all-in-one/src/components/TransactionItem.jac +55 -0
  8. jac_client/examples/all-in-one/src/components/TransactionList.jac +37 -0
  9. jac_client/examples/all-in-one/src/components/navigation.jac +132 -0
  10. jac_client/examples/all-in-one/src/constants/categories.jac +37 -0
  11. jac_client/examples/all-in-one/src/constants/clients.jac +13 -0
  12. jac_client/examples/all-in-one/src/context/BudgetContext.jac +28 -0
  13. jac_client/examples/all-in-one/src/hooks/useBudget.jac +116 -0
  14. jac_client/examples/all-in-one/src/hooks/useLocalStorage.jac +36 -0
  15. jac_client/examples/all-in-one/src/pages/BudgetPlanner.cl.jac +70 -0
  16. jac_client/examples/all-in-one/src/pages/BudgetPlanner.jac +126 -0
  17. jac_client/examples/all-in-one/src/pages/FeaturesTest.cl.jac +552 -0
  18. jac_client/examples/all-in-one/src/pages/FeaturesTest.jac +126 -0
  19. jac_client/examples/all-in-one/src/pages/LandingPage.jac +101 -0
  20. jac_client/examples/all-in-one/src/pages/loginPage.jac +132 -0
  21. jac_client/examples/all-in-one/src/pages/nestedDemo.jac +61 -0
  22. jac_client/examples/all-in-one/src/pages/notFound.jac +24 -0
  23. jac_client/examples/all-in-one/src/pages/signupPage.jac +133 -0
  24. jac_client/examples/all-in-one/src/utils/formatters.jac +52 -0
  25. jac_client/examples/asset-serving/css-with-image/src/app.jac +3 -3
  26. jac_client/examples/asset-serving/image-asset/src/app.jac +3 -3
  27. jac_client/examples/asset-serving/import-alias/src/app.jac +3 -3
  28. jac_client/examples/basic/src/app.jac +3 -3
  29. jac_client/examples/basic-auth/src/app.jac +31 -37
  30. jac_client/examples/basic-auth-with-router/src/app.jac +16 -16
  31. jac_client/examples/basic-full-stack/src/app.jac +24 -30
  32. jac_client/examples/css-styling/js-styling/src/app.jac +5 -5
  33. jac_client/examples/css-styling/material-ui/src/app.jac +5 -5
  34. jac_client/examples/css-styling/pure-css/src/app.jac +5 -5
  35. jac_client/examples/css-styling/sass-example/src/app.jac +5 -5
  36. jac_client/examples/css-styling/styled-components/src/app.jac +5 -5
  37. jac_client/examples/css-styling/tailwind-example/src/app.jac +5 -5
  38. jac_client/examples/full-stack-with-auth/src/app.jac +16 -16
  39. jac_client/examples/ts-support/src/app.jac +4 -4
  40. jac_client/examples/with-router/src/app.jac +4 -4
  41. jac_client/plugin/cli.jac +155 -203
  42. jac_client/plugin/client_runtime.cl.jac +5 -1
  43. jac_client/plugin/impl/client.impl.jac +74 -12
  44. jac_client/plugin/plugin_config.jac +11 -11
  45. jac_client/plugin/src/compiler.jac +2 -1
  46. jac_client/plugin/src/impl/babel_processor.impl.jac +22 -17
  47. jac_client/plugin/src/impl/compiler.impl.jac +57 -18
  48. jac_client/plugin/src/impl/vite_bundler.impl.jac +66 -102
  49. jac_client/plugin/src/package_installer.jac +1 -1
  50. jac_client/plugin/src/vite_bundler.jac +1 -0
  51. jac_client/tests/conftest.py +10 -8
  52. jac_client/tests/fixtures/spawn_test/app.jac +15 -18
  53. jac_client/tests/fixtures/with-ts/app.jac +4 -4
  54. jac_client/tests/test_cli.py +99 -45
  55. jac_client/tests/test_it.py +290 -79
  56. {jac_client-0.2.5.dist-info → jac_client-0.2.7.dist-info}/METADATA +16 -7
  57. jac_client-0.2.7.dist-info/RECORD +97 -0
  58. jac_client-0.2.5.dist-info/RECORD +0 -74
  59. {jac_client-0.2.5.dist-info → jac_client-0.2.7.dist-info}/WHEEL +0 -0
  60. {jac_client-0.2.5.dist-info → jac_client-0.2.7.dist-info}/entry_points.txt +0 -0
  61. {jac_client-0.2.5.dist-info → jac_client-0.2.7.dist-info}/top_level.txt +0 -0
@@ -57,12 +57,13 @@ impl JacClient.get_client_bundle_builder -> ViteClientBundleBuilder {
57
57
  # Fallback to base_path_dir if no project root found
58
58
  base_path = base_path_dir;
59
59
  }
60
- # package.json should only exist in .client-build/.jac-client.configs/
61
- generated_package_json = base_path / '.client-build' / '.jac-client.configs' / 'package.json';
60
+ # Use ViteBundler to get the client directory
61
+ bundler = ViteBundler(base_path);
62
+ client_dir = bundler._get_client_dir();
63
+ # package.json should only exist in .jac/client/configs/
64
+ generated_package_json = client_dir / 'configs' / 'package.json';
62
65
  # Generate package.json if it doesn't exist
63
66
  if not generated_package_json.exists() {
64
- # Use ViteBundler to generate package.json from config.json
65
- bundler = ViteBundler(base_path);
66
67
  generated_path = bundler.create_package_json();
67
68
  # Verify the file was created and resolve to absolute path
68
69
  if not generated_path.exists() {
@@ -80,7 +81,7 @@ impl JacClient.get_client_bundle_builder -> ViteClientBundleBuilder {
80
81
  f'package.json not found at {package_json_path}. Expected at {generated_package_json}'
81
82
  ) ;
82
83
  }
83
- output_dir = base_path / '.client-build' / 'dist';
84
+ output_dir = client_dir / 'dist';
84
85
  runtime_path = Path(__file__).with_name('client_runtime.cl.jac');
85
86
  return ViteClientBundleBuilder(
86
87
  runtime_path=runtime_path,
@@ -106,7 +107,7 @@ impl JacClientModuleIntrospector.render_page(
106
107
  raise ValueError(f"Client function '{function_name}' not found") ;
107
108
  }
108
109
  bundle_hash = self.ensure_bundle();
109
- import from jaclang.project.config { find_project_root }
110
+ import from jaclang.project.config { find_project_root, get_config }
110
111
  # Find project root by looking for jac.toml (base_path_dir might be src/ for entry files)
111
112
  base_path_dir = Path(Jac.base_path_dir);
112
113
  project_root_result = find_project_root(base_path_dir);
@@ -116,16 +117,77 @@ impl JacClientModuleIntrospector.render_page(
116
117
  # Fallback to base_path_dir if no project root found
117
118
  base_path = base_path_dir;
118
119
  }
119
- dist_dir = base_path / '.client-build' / 'dist';
120
+ # Get client directory from config or use default
121
+ config = get_config();
122
+ if config is not None {
123
+ dist_dir = config.get_client_dir() / 'dist';
124
+ } else {
125
+ dist_dir = base_path / '.jac' / 'client' / 'dist';
126
+ }
120
127
  css_link = '';
121
- css_file = dist_dir / 'main.css';
128
+ css_file = dist_dir / 'styles.css';
122
129
  if css_file.exists() {
123
130
  css_hash = hashlib.sha256(css_file.read_bytes()).hexdigest()[:8];
124
- css_link = f'<link rel="stylesheet" href="/static/main.css?hash={css_hash}"/>';
131
+ css_link = f'<link rel="stylesheet" href="/static/styles.css?hash={css_hash}"/>';
132
+ }
133
+ # Get meta data from config
134
+ client_cfg = config.get_plugin_config("client") if config else None;
135
+ meta_data = client_cfg.get("app_meta_data", {}) if client_cfg else {};
136
+ charset = meta_data.get("charset", "UTF-8");
137
+ title = meta_data.get("title", function_name);
138
+ viewport = meta_data.get("viewport", "width=device-width, initial-scale=1");
139
+ description = meta_data.get("description", None);
140
+ robots = meta_data.get("robots", "index, follow");
141
+ canonical = meta_data.get("canonical", None);
142
+ og_type = meta_data.get("og_type", "website");
143
+ og_title = meta_data.get("og_title", title);
144
+ og_description = meta_data.get("og_description", None);
145
+ og_url = meta_data.get("og_url", None);
146
+ og_image = meta_data.get("og_image", None);
147
+ theme_color = meta_data.get("theme_color", "#ffffff");
148
+ icon = meta_data.get("icon", None);
149
+ # Build head content from TOML metadata
150
+ head_content = f'<meta charset="{html.escape(charset)}"/>\n <meta name="viewport" content="{html.escape(
151
+ viewport
152
+ )}"/>\n <title>{html.escape(title)}</title>';
153
+ head_content += f'\n <meta name="robots" content="{html.escape(robots)}"/>';
154
+ head_content += f'\n <meta name="theme-color" content="{html.escape(
155
+ theme_color
156
+ )}"/>';
157
+ head_content += f'\n <meta property="og:type" content="{html.escape(
158
+ og_type
159
+ )}"/>';
160
+ head_content += f'\n <meta property="og:title" content="{html.escape(
161
+ og_title
162
+ )}"/>';
163
+ if description {
164
+ head_content += f'\n <meta name="description" content="{html.escape(
165
+ description
166
+ )}"/>';
167
+ }
168
+ if canonical {
169
+ head_content += f'\n <link rel="canonical" href="{html.escape(
170
+ canonical
171
+ )}"/>';
172
+ }
173
+ if icon {
174
+ head_content += f'\n <link rel="icon" href="{html.escape(icon)}"/>';
175
+ }
176
+ if og_url {
177
+ head_content += f'\n <meta property="og:url" content="{html.escape(
178
+ og_url
179
+ )}"/>';
180
+ }
181
+ if og_image {
182
+ head_content += f'\n <meta property="og:image" content="{html.escape(
183
+ og_image
184
+ )}"/>';
185
+ }
186
+ if og_description {
187
+ head_content += f'\n <meta property="og:description" content="{html.escape(
188
+ og_description
189
+ )}"/>';
125
190
  }
126
- head_content = f'<meta charset="utf-8"/>\n <title>{html.escape(
127
- function_name
128
- )}</title>';
129
191
  if css_link {
130
192
  head_content += f"\n {css_link}";
131
193
  }
@@ -80,7 +80,7 @@ class JacClientPluginConfig {
80
80
  "name": "npm",
81
81
  "dev_name": "npm.dev",
82
82
  "cli_flag": "--cl",
83
- "install_dir": ".client-build/.jac-client.configs",
83
+ "install_dir": ".jac/client/configs",
84
84
  "install_handler": _npm_install_handler,
85
85
  "install_all_handler": _npm_install_all_handler,
86
86
  "remove_handler": _npm_remove_handler
@@ -152,13 +152,13 @@ def _regenerate_and_install(project_dir: Path) -> None {
152
152
  bundler = ViteBundler(project_dir);
153
153
  bundler.create_package_json();
154
154
 
155
- # Install to .client-build/ directory where babel processor expects it
156
- build_dir = project_dir / '.client-build';
157
- build_dir.mkdir(exist_ok=True);
155
+ # Install to .jac/client/ directory where babel processor expects it
156
+ client_dir = bundler._get_client_dir();
157
+ client_dir.mkdir(parents=True, exist_ok=True);
158
158
 
159
- # Copy package.json to .client-build/ for npm install
160
- configs_package_json = build_dir / '.jac-client.configs' / 'package.json';
161
- build_package_json = build_dir / 'package.json';
159
+ # Copy package.json to .jac/client/ for npm install
160
+ configs_package_json = client_dir / 'configs' / 'package.json';
161
+ build_package_json = client_dir / 'package.json';
162
162
  if configs_package_json.exists() {
163
163
  shutil.copy2(configs_package_json, build_package_json);
164
164
  }
@@ -166,7 +166,7 @@ def _regenerate_and_install(project_dir: Path) -> None {
166
166
  try {
167
167
  subprocess.run(
168
168
  ["npm", "install"],
169
- cwd=build_dir,
169
+ cwd=client_dir,
170
170
  check=True,
171
171
  capture_output=True,
172
172
  text=True
@@ -182,10 +182,10 @@ def _regenerate_and_install(project_dir: Path) -> None {
182
182
  if build_package_json.exists() {
183
183
  build_package_json.unlink();
184
184
  }
185
- # Move package-lock.json to .jac-client.configs/ if it exists
186
- build_package_lock = build_dir / 'package-lock.json';
185
+ # Move package-lock.json to configs/ if it exists
186
+ build_package_lock = client_dir / 'package-lock.json';
187
187
  if build_package_lock.exists() {
188
- configs_package_lock = build_dir / '.jac-client.configs' / 'package-lock.json';
188
+ configs_package_lock = client_dir / 'configs' / 'package-lock.json';
189
189
  if configs_package_lock.exists() {
190
190
  configs_package_lock.unlink();
191
191
  }
@@ -52,6 +52,7 @@ class ViteCompiler {
52
52
  source_root: (Path | None) = None
53
53
  ) -> None;
54
54
 
55
+ def _get_client_dir(self: ViteCompiler) -> Path;
55
56
  def _copy_js_file(self: ViteCompiler, js_path: Path, source_root: Path) -> None;
56
57
  def _copy_ts_file(self: ViteCompiler, ts_path: Path, source_root: Path) -> None;
57
58
  def _copy_asset_file(
@@ -59,7 +60,7 @@ class ViteCompiler {
59
60
  ) -> None;
60
61
 
61
62
  def copy_root_assets(self: ViteCompiler) -> None;
62
- def create_entry_file(self: ViteCompiler) -> None;
63
+ def create_entry_file(self: ViteCompiler, module_path: Path) -> None;
63
64
  def compile_and_bundle(
64
65
  self: ViteCompiler, module: ModuleType, module_path: Path
65
66
  ) -> tuple[str, str, list[str], list[str]];
@@ -17,21 +17,21 @@ impl BabelProcessor.compile(self: BabelProcessor) -> None {
17
17
  bundler._ensure_root_package_json();
18
18
  try {
19
19
  # Ensure dependencies are installed (check if node_modules exists)
20
- build_dir = self.project_dir / '.client-build';
21
- node_modules = build_dir / 'node_modules';
20
+ client_dir = bundler._get_client_dir();
21
+ node_modules = client_dir / 'node_modules';
22
22
  if not node_modules.exists() {
23
- # Temporarily copy package.json to .client-build/ for npm install
24
- build_package_json = build_dir / 'package.json';
25
- configs_package_json = build_dir / '.jac-client.configs' / 'package.json';
23
+ # Temporarily copy package.json to .jac/client/ for npm install
24
+ build_package_json = client_dir / 'package.json';
25
+ configs_package_json = client_dir / 'configs' / 'package.json';
26
26
  if configs_package_json.exists() and not build_package_json.exists() {
27
27
  import shutil;
28
28
  shutil.copy2(configs_package_json, build_package_json);
29
29
  }
30
30
  try {
31
- # Install to .client-build/node_modules
31
+ # Install to .jac/client/node_modules
32
32
  subprocess.run(
33
33
  ['npm', 'install'],
34
- cwd=build_dir,
34
+ cwd=client_dir,
35
35
  check=True,
36
36
  capture_output=True,
37
37
  text=True
@@ -47,27 +47,32 @@ impl BabelProcessor.compile(self: BabelProcessor) -> None {
47
47
  }
48
48
  }
49
49
 
50
- # Temporarily copy package.json to .client-build/ for npm run compile
51
- build_package_json = build_dir / 'package.json';
52
- configs_package_json = build_dir / '.jac-client.configs' / 'package.json';
50
+ # Temporarily copy package.json to .jac/client/ for npm run compile
51
+ build_package_json = client_dir / 'package.json';
52
+ configs_package_json = client_dir / 'configs' / 'package.json';
53
53
  if configs_package_json.exists() and not build_package_json.exists() {
54
54
  import shutil;
55
55
  shutil.copy2(configs_package_json, build_package_json);
56
56
  }
57
57
  command = ['npm', 'run', 'compile'];
58
- subprocess.run(
59
- command, cwd=build_dir, check=True, capture_output=True, text=True
58
+ result = subprocess.run(
59
+ command, cwd=client_dir, capture_output=True, text=True
60
60
  );
61
+ if result.returncode != 0 {
62
+ # Show the actual error from npm/babel
63
+ error_output = result.stderr or result.stdout or "Unknown error";
64
+ raise RuntimeError(f"Client bundle compilation failed:\n{error_output}") ;
65
+ }
61
66
  } finally {
62
- # Clean up temporary package.json in .client-build/
63
- build_package_json = build_dir / 'package.json';
67
+ # Clean up temporary package.json in .jac/client/
68
+ build_package_json = client_dir / 'package.json';
64
69
  if build_package_json.exists() {
65
70
  build_package_json.unlink();
66
71
  }
67
- # Move package-lock.json to .jac-client.configs/ if it exists
68
- build_package_lock = build_dir / 'package-lock.json';
72
+ # Move package-lock.json to configs/ if it exists
73
+ build_package_lock = client_dir / 'package-lock.json';
69
74
  if build_package_lock.exists() {
70
- configs_package_lock = build_dir / '.jac-client.configs' / 'package-lock.json';
75
+ configs_package_lock = client_dir / 'configs' / 'package-lock.json';
71
76
  if configs_package_lock.exists() {
72
77
  configs_package_lock.unlink();
73
78
  }
@@ -1,5 +1,20 @@
1
- """Compile module and dependencies, then bundle with Vite."""
1
+ """Get the client build directory from project config."""
2
+ impl ViteCompiler._get_client_dir(self: ViteCompiler) -> Path {
3
+ # Try to get from project config
4
+ try {
5
+ import from jaclang.project.config { get_config }
6
+ config = get_config();
7
+ if config is not None {
8
+ return config.get_client_dir();
9
+ }
10
+ } except ImportError {
11
+ pass;
12
+ }
13
+ # Fallback to default
14
+ return self.project_dir / '.jac' / 'client';
15
+ }
2
16
 
17
+ """Compile module and dependencies, then bundle with Vite."""
3
18
  impl ViteCompiler.compile_and_bundle(
4
19
  self: ViteCompiler, module: ModuleType, module_path: Path
5
20
  ) -> tuple[str, str, list[str], list[str]] {
@@ -16,14 +31,13 @@ impl ViteCompiler.compile_and_bundle(
16
31
  collected_globals=collected_globals
17
32
  );
18
33
  self.copy_root_assets();
19
- self.create_entry_file();
34
+ self.create_entry_file(module_path);
20
35
  self.babel_processor.compile();
36
+ client_dir = self._get_client_dir();
21
37
  self.babel_processor.copy_assets_after_compile(
22
- self.compiled_dir,
23
- (self.project_dir / '.client-build' / 'build'),
24
- self.asset_processor
38
+ self.compiled_dir, (client_dir / 'build'), self.asset_processor
25
39
  );
26
- entry_file = self.project_dir / '.client-build' / 'build' / 'main.js';
40
+ entry_file = client_dir / 'build' / '_entry.js';
27
41
  self.vite_bundler.build(entry_file=entry_file);
28
42
  (bundle_code, bundle_hash) = self.vite_bundler.read_bundle();
29
43
  client_exports = sorted(collected_exports);
@@ -32,9 +46,12 @@ impl ViteCompiler.compile_and_bundle(
32
46
  }
33
47
 
34
48
  """Create the main entry file for Vite bundling."""
35
- impl ViteCompiler.create_entry_file(self: ViteCompiler) -> None {
36
- entry_file = self.compiled_dir / 'main.js';
37
- entry_content = 'import React from "react";\nimport { createRoot } from "react-dom/client";\nimport { app as App } from "./app.js";\n\nconst root = createRoot(document.getElementById("root"));\nroot.render(<App />);\n';
49
+ impl ViteCompiler.create_entry_file(self: ViteCompiler, module_path: Path) -> None {
50
+ # Use _entry.js to avoid conflict with compiled modules that may be named main.js
51
+ entry_file = self.compiled_dir / '_entry.js';
52
+ # Derive the app module filename from the entry point (e.g., main.jac -> main.js, app.jac -> app.js)
53
+ app_module_name = module_path.stem;
54
+ entry_content = f'import React from "react";\nimport {{ createRoot }} from "react-dom/client";\nimport {{ app as App }} from "./{app_module_name}.js";\n\nconst root = createRoot(document.getElementById("root"));\nroot.render(<App />);\n';
38
55
  entry_file.write_text(entry_content, encoding='utf-8');
39
56
  }
40
57
 
@@ -46,7 +63,7 @@ impl ViteCompiler.copy_root_assets(self: ViteCompiler) -> None {
46
63
  self.asset_processor.copy_assets(root_assets_dir, compiled_assets_dir);
47
64
  }
48
65
  # Copy configured_asset files from root assets/ to build assets/ (bypassing compiled)
49
- build_assets_dir = self.project_dir / '.client-build' / 'build' / 'assets';
66
+ build_assets_dir = self._get_client_dir() / 'build' / 'assets';
50
67
  if (root_assets_dir.exists() and root_assets_dir.is_dir()) {
51
68
  self.asset_processor.copy_custom_asset_types(root_assets_dir, build_assets_dir);
52
69
  }
@@ -149,9 +166,29 @@ impl ViteCompiler.compile_dependencies_recursively(
149
166
  combined_js = self.jac_compiler.add_runtime_imports(module_js);
150
167
  try {
151
168
  relative_path = module_path.relative_to(source_root);
152
- output_path = self.compiled_dir / relative_path.with_suffix('.js');
169
+ # Handle compound extensions like .cl.jac, .impl.jac -> .js
170
+ rel_str = str(relative_path);
171
+ for compound_ext in ['.cl.jac', '.impl.jac', '.test.jac'] {
172
+ if rel_str.endswith(compound_ext) {
173
+ rel_str = rel_str[:-len(compound_ext)] + '.js';
174
+ break;
175
+ }
176
+ } else {
177
+ rel_str = str(relative_path.with_suffix('.js'));
178
+ }
179
+ output_path = self.compiled_dir / rel_str;
153
180
  } except ValueError {
154
- output_path = self.compiled_dir / f"{module_path.stem}.js";
181
+ # Handle compound extensions in filename
182
+ name = module_path.name;
183
+ for compound_ext in ['.cl.jac', '.impl.jac', '.test.jac'] {
184
+ if name.endswith(compound_ext) {
185
+ name = name[:-len(compound_ext)] + '.js';
186
+ break;
187
+ }
188
+ } else {
189
+ name = module_path.stem + '.js';
190
+ }
191
+ output_path = self.compiled_dir / name;
155
192
  }
156
193
  output_path.parent.mkdir(parents=True, exist_ok=True);
157
194
  output_path.write_text(combined_js, encoding='utf-8');
@@ -228,19 +265,21 @@ impl ViteCompiler.init(
228
265
  ) ;
229
266
  }
230
267
  self.vite_package_json = vite_package_json;
231
- # If package.json is in .client-build/.jac-client.configs/, go up two levels to get project root
268
+ # Detect project root: package.json may be in .jac/client/configs/ or project root
232
269
  if (
233
- vite_package_json.parent.name == '.jac-client.configs'
234
- and vite_package_json.parent.parent.name == '.client-build'
270
+ vite_package_json.parent.name == 'configs'
271
+ and vite_package_json.parent.parent.name == 'client'
272
+ and vite_package_json.parent.parent.parent.name == '.jac'
235
273
  ) {
236
- self.project_dir = vite_package_json.parent.parent.parent;
237
- } elif (vite_package_json.parent.name == '.jac-client.configs') {
274
+ # .jac/client/configs/package.json -> go up 3 levels to project root
275
+ self.project_dir = vite_package_json.parent.parent.parent.parent;
276
+ } elif (vite_package_json.parent.name == 'configs') {
238
277
  self.project_dir = vite_package_json.parent.parent;
239
278
  } else {
240
279
  self.project_dir = vite_package_json.parent;
241
280
  }
242
281
  self.runtime_path = runtime_path;
243
- self.compiled_dir = self.project_dir / '.client-build' / 'compiled';
282
+ self.compiled_dir = self._get_client_dir() / 'compiled';
244
283
  self.jac_compiler = JacToJSCompiler(
245
284
  compile_to_js_func, extract_exports_func, extract_globals_func
246
285
  );