jac-client 0.2.8__py3-none-any.whl → 0.2.11__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/examples/all-in-one/button.jac +4 -3
- jac_client/examples/all-in-one/components/CategoryFilter.jac +36 -24
- jac_client/examples/all-in-one/components/Header.jac +12 -8
- jac_client/examples/all-in-one/components/ProfitOverview.jac +49 -35
- jac_client/examples/all-in-one/components/Summary.jac +59 -36
- jac_client/examples/all-in-one/components/TransactionForm.jac +142 -112
- jac_client/examples/all-in-one/components/TransactionItem.jac +37 -30
- jac_client/examples/all-in-one/components/TransactionList.jac +33 -26
- jac_client/examples/all-in-one/components/button.jac +4 -3
- jac_client/examples/all-in-one/components/navigation.jac +111 -117
- jac_client/examples/all-in-one/constants/categories.jac +23 -24
- jac_client/examples/all-in-one/constants/clients.jac +7 -8
- jac_client/examples/all-in-one/context/BudgetContext.jac +9 -6
- jac_client/examples/all-in-one/hooks/useBudget.jac +18 -12
- jac_client/examples/all-in-one/hooks/useLocalStorage.jac +14 -13
- jac_client/examples/all-in-one/main.jac +542 -0
- jac_client/examples/all-in-one/pages/BudgetPlanner.jac +26 -12
- jac_client/examples/all-in-one/pages/FeaturesTest.jac +43 -12
- jac_client/examples/all-in-one/pages/LandingPage.jac +113 -90
- jac_client/examples/all-in-one/pages/budget_planner_ui.cl.jac +65 -0
- jac_client/examples/all-in-one/pages/features_test_ui.cl.jac +675 -0
- jac_client/examples/all-in-one/pages/loginPage.jac +114 -119
- jac_client/examples/all-in-one/pages/nestedDemo.jac +44 -51
- jac_client/examples/all-in-one/pages/notFound.jac +15 -21
- jac_client/examples/all-in-one/pages/signupPage.jac +113 -119
- jac_client/examples/all-in-one/utils/formatters.jac +5 -8
- jac_client/examples/asset-serving/css-with-image/main.jac +92 -0
- jac_client/examples/asset-serving/image-asset/main.jac +56 -0
- jac_client/examples/asset-serving/import-alias/main.jac +109 -0
- jac_client/examples/basic/main.jac +23 -0
- jac_client/examples/basic-auth/main.jac +363 -0
- jac_client/examples/basic-auth-with-router/main.jac +451 -0
- jac_client/examples/basic-full-stack/main.jac +362 -0
- jac_client/examples/css-styling/js-styling/main.jac +63 -0
- jac_client/examples/css-styling/material-ui/main.jac +122 -0
- jac_client/examples/css-styling/pure-css/main.jac +55 -0
- jac_client/examples/css-styling/sass-example/main.jac +55 -0
- jac_client/examples/css-styling/styled-components/main.jac +62 -0
- jac_client/examples/css-styling/tailwind-example/main.jac +74 -0
- jac_client/examples/full-stack-with-auth/main.jac +696 -0
- jac_client/examples/little-x/main.jac +681 -0
- jac_client/examples/little-x/src/submit-button.jac +15 -14
- jac_client/examples/nested-folders/nested-advance/main.jac +26 -0
- jac_client/examples/nested-folders/nested-advance/src/ButtonRoot.jac +4 -6
- jac_client/examples/nested-folders/nested-advance/src/level1/ButtonSecondL.jac +9 -13
- jac_client/examples/nested-folders/nested-advance/src/level1/Card.jac +29 -32
- jac_client/examples/nested-folders/nested-advance/src/level1/level2/ButtonThirdL.jac +12 -18
- jac_client/examples/nested-folders/nested-basic/{src/app.jac → main.jac} +7 -5
- jac_client/examples/nested-folders/nested-basic/src/button.jac +4 -3
- jac_client/examples/nested-folders/nested-basic/src/components/button.jac +4 -3
- jac_client/examples/ts-support/main.jac +35 -0
- jac_client/examples/with-router/main.jac +286 -0
- jac_client/plugin/cli.jac +491 -411
- jac_client/plugin/client.jac +25 -0
- jac_client/plugin/client_runtime.cl.jac +10 -4
- jac_client/plugin/impl/client.impl.jac +96 -55
- jac_client/plugin/impl/client_runtime.impl.jac +155 -1
- jac_client/plugin/plugin_config.jac +211 -29
- jac_client/plugin/src/__init__.jac +0 -2
- jac_client/plugin/src/compiler.jac +0 -1
- jac_client/plugin/src/config_loader.jac +1 -0
- jac_client/plugin/src/desktop_config.jac +31 -0
- jac_client/plugin/src/impl/compiler.impl.jac +49 -17
- jac_client/plugin/src/impl/config_loader.impl.jac +8 -0
- jac_client/plugin/src/impl/desktop_config.impl.jac +191 -0
- jac_client/plugin/src/impl/jac_to_js.impl.jac +5 -1
- jac_client/plugin/src/impl/package_installer.impl.jac +20 -20
- jac_client/plugin/src/impl/vite_bundler.impl.jac +191 -64
- jac_client/plugin/src/targets/desktop/sidecar/main.py +144 -0
- jac_client/plugin/src/targets/desktop_target.jac +37 -0
- jac_client/plugin/src/targets/impl/desktop_target.impl.jac +2347 -0
- jac_client/plugin/src/targets/impl/registry.impl.jac +64 -0
- jac_client/plugin/src/targets/impl/web_target.impl.jac +157 -0
- jac_client/plugin/src/targets/register.jac +21 -0
- jac_client/plugin/src/targets/registry.jac +87 -0
- jac_client/plugin/src/targets/web_target.jac +35 -0
- jac_client/plugin/src/vite_bundler.jac +6 -0
- jac_client/plugin/utils/__init__.jac +3 -0
- jac_client/plugin/utils/bun_installer.jac +16 -0
- jac_client/plugin/utils/impl/bun_installer.impl.jac +99 -0
- jac_client/templates/client.jacpack +72 -0
- jac_client/templates/fullstack.jacpack +61 -0
- jac_client/tests/conftest.py +103 -47
- jac_client/tests/fixtures/spawn_test/app.jac +49 -52
- jac_client/tests/fixtures/with-ts/app.jac +27 -27
- jac_client/tests/test_cli.py +182 -71
- jac_client/tests/test_e2e.py +232 -0
- jac_client/tests/test_helpers.py +58 -0
- jac_client/tests/test_it.py +91 -135
- jac_client/tests/test_it_desktop.py +891 -0
- {jac_client-0.2.8.dist-info → jac_client-0.2.11.dist-info}/METADATA +6 -6
- jac_client-0.2.11.dist-info/RECORD +113 -0
- {jac_client-0.2.8.dist-info → jac_client-0.2.11.dist-info}/WHEEL +1 -1
- jac_client/examples/all-in-one/app.jac +0 -573
- jac_client/examples/all-in-one/pages/BudgetPlanner.cl.jac +0 -70
- jac_client/examples/all-in-one/pages/FeaturesTest.cl.jac +0 -552
- jac_client/examples/asset-serving/css-with-image/src/app.jac +0 -88
- jac_client/examples/asset-serving/image-asset/src/app.jac +0 -55
- jac_client/examples/asset-serving/import-alias/src/app.jac +0 -111
- jac_client/examples/basic/src/app.jac +0 -21
- jac_client/examples/basic-auth/src/app.jac +0 -371
- jac_client/examples/basic-auth-with-router/src/app.jac +0 -464
- jac_client/examples/basic-full-stack/src/app.jac +0 -359
- jac_client/examples/css-styling/js-styling/src/app.jac +0 -84
- jac_client/examples/css-styling/material-ui/src/app.jac +0 -122
- jac_client/examples/css-styling/pure-css/src/app.jac +0 -64
- jac_client/examples/css-styling/sass-example/src/app.jac +0 -64
- jac_client/examples/css-styling/styled-components/src/app.jac +0 -71
- jac_client/examples/css-styling/tailwind-example/src/app.jac +0 -63
- jac_client/examples/full-stack-with-auth/src/app.jac +0 -722
- jac_client/examples/little-x/src/app.jac +0 -719
- jac_client/examples/nested-folders/nested-advance/src/app.jac +0 -35
- jac_client/examples/ts-support/src/app.jac +0 -35
- jac_client/examples/with-router/src/app.jac +0 -323
- jac_client/plugin/src/babel_processor.jac +0 -18
- jac_client/plugin/src/impl/babel_processor.impl.jac +0 -89
- jac_client-0.2.8.dist-info/RECORD +0 -97
- {jac_client-0.2.8.dist-info → jac_client-0.2.11.dist-info}/entry_points.txt +0 -0
- {jac_client-0.2.8.dist-info → jac_client-0.2.11.dist-info}/top_level.txt +0 -0
|
@@ -44,17 +44,14 @@ impl ViteBundler.create_package_json(
|
|
|
44
44
|
}
|
|
45
45
|
dependencies = package_config.get('dependencies', {});
|
|
46
46
|
dev_dependencies = package_config.get('devDependencies', {});
|
|
47
|
+
# Vite handles JSX/TSX transpilation natively with Bun - no Babel compile step needed
|
|
47
48
|
scripts = {
|
|
48
|
-
'build': '
|
|
49
|
+
'build': 'vite build --config .jac/client/configs/vite.config.js',
|
|
49
50
|
'dev': 'vite dev --config .jac/client/configs/vite.config.js',
|
|
50
|
-
'preview': 'vite preview --config .jac/client/configs/vite.config.js'
|
|
51
|
-
'compile': 'babel compiled --out-dir build --extensions ".jsx,.js" --out-file-extension .js'
|
|
51
|
+
'preview': 'vite preview --config .jac/client/configs/vite.config.js'
|
|
52
52
|
};
|
|
53
53
|
user_scripts = package_config.get('scripts', {});
|
|
54
54
|
scripts.update(user_scripts);
|
|
55
|
-
babel_config = {
|
|
56
|
-
'presets': [['@babel/preset-env', {'modules': False}], '@babel/preset-react']
|
|
57
|
-
};
|
|
58
55
|
package_data = {
|
|
59
56
|
'name': name,
|
|
60
57
|
'version': package_config.get('version', '1.0.0'),
|
|
@@ -63,8 +60,7 @@ impl ViteBundler.create_package_json(
|
|
|
63
60
|
'main': 'index.js',
|
|
64
61
|
'scripts': scripts,
|
|
65
62
|
'dependencies': dependencies,
|
|
66
|
-
'devDependencies': dev_dependencies
|
|
67
|
-
'babel': babel_config
|
|
63
|
+
'devDependencies': dev_dependencies
|
|
68
64
|
};
|
|
69
65
|
for (key, value) in package_config.items() {
|
|
70
66
|
if (
|
|
@@ -78,6 +74,8 @@ impl ViteBundler.create_package_json(
|
|
|
78
74
|
}
|
|
79
75
|
# Generate tsconfig.json during build time
|
|
80
76
|
self.create_tsconfig();
|
|
77
|
+
# Generate config files (postcss, tailwind, etc.) from jac.toml
|
|
78
|
+
self.create_config_files();
|
|
81
79
|
return package_json_path;
|
|
82
80
|
}
|
|
83
81
|
|
|
@@ -129,22 +127,22 @@ impl ViteBundler.create_tsconfig(self: ViteBundler) -> Path {
|
|
|
129
127
|
}
|
|
130
128
|
|
|
131
129
|
"""
|
|
132
|
-
Clean up root package.json and move
|
|
130
|
+
Clean up root package.json and move bun.lockb to configs/.
|
|
133
131
|
|
|
134
|
-
Remove root package.json and move
|
|
132
|
+
Remove root package.json and move bun.lockb to configs/.
|
|
135
133
|
"""
|
|
136
134
|
impl ViteBundler._cleanup_root_package_files(self: ViteBundler) -> None {
|
|
137
135
|
root_package_json = self.project_dir / 'package.json';
|
|
138
|
-
|
|
136
|
+
root_bun_lockb = self.project_dir / 'bun.lockb';
|
|
139
137
|
build_dir = self._get_client_dir();
|
|
140
138
|
configs_dir = build_dir / 'configs';
|
|
141
|
-
|
|
142
|
-
if
|
|
139
|
+
configs_bun_lockb = configs_dir / 'bun.lockb';
|
|
140
|
+
if root_bun_lockb.exists() {
|
|
143
141
|
configs_dir.mkdir(exist_ok=True);
|
|
144
|
-
if
|
|
145
|
-
|
|
142
|
+
if configs_bun_lockb.exists() {
|
|
143
|
+
configs_bun_lockb.unlink();
|
|
146
144
|
}
|
|
147
|
-
shutil.move(str(
|
|
145
|
+
shutil.move(str(root_bun_lockb), str(configs_bun_lockb));
|
|
148
146
|
}
|
|
149
147
|
if root_package_json.exists() {
|
|
150
148
|
root_package_json.unlink();
|
|
@@ -152,7 +150,7 @@ impl ViteBundler._cleanup_root_package_files(self: ViteBundler) -> None {
|
|
|
152
150
|
}
|
|
153
151
|
|
|
154
152
|
"""
|
|
155
|
-
Ensure root package.json exists temporarily for
|
|
153
|
+
Ensure root package.json exists temporarily for bun commands.
|
|
156
154
|
|
|
157
155
|
Create root package.json temporarily if it doesn't exist.
|
|
158
156
|
"""
|
|
@@ -301,26 +299,76 @@ impl ViteBundler.create_vite_config(self: ViteBundler, entry_file: Path) -> Path
|
|
|
301
299
|
else '';
|
|
302
300
|
config_content = f'''import {{ defineConfig }} from "vite";
|
|
303
301
|
import path from "path";
|
|
302
|
+
import fs from "fs";
|
|
304
303
|
import {{ fileURLToPath }} from "url";
|
|
305
304
|
{imports_section}const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
306
305
|
// Config is in configs/ inside .jac/client/, so go up one level to .jac/client/, then up two more to project root
|
|
307
306
|
const buildDir = path.resolve(__dirname, "..");
|
|
308
307
|
const projectRoot = path.resolve(__dirname, "../../..");
|
|
309
308
|
|
|
309
|
+
// Jac source mapper plugin - maps errors back to original .jac files
|
|
310
|
+
function jacSourceMapper() {{
|
|
311
|
+
const sourceMap = new Map(); // compiled path -> original jac path
|
|
312
|
+
|
|
313
|
+
return {{
|
|
314
|
+
name: 'jac-source-mapper',
|
|
315
|
+
enforce: 'pre',
|
|
316
|
+
|
|
317
|
+
// Extract source mapping from compiled files
|
|
318
|
+
transform(code, id) {{
|
|
319
|
+
if (id.includes('/compiled/') && id.endsWith('.js')) {{
|
|
320
|
+
const match = code.match(/^\\/\\* Source: (.+?) \\*\\//);
|
|
321
|
+
if (match) {{
|
|
322
|
+
sourceMap.set(id, match[1]);
|
|
323
|
+
}}
|
|
324
|
+
}}
|
|
325
|
+
return null;
|
|
326
|
+
}},
|
|
327
|
+
|
|
328
|
+
// Enhance error messages with original source info
|
|
329
|
+
buildEnd() {{
|
|
330
|
+
// Store source map for error reporting
|
|
331
|
+
this._jacSourceMap = sourceMap;
|
|
332
|
+
}},
|
|
333
|
+
|
|
334
|
+
// Handle resolve errors to show original source
|
|
335
|
+
resolveId(source, importer) {{
|
|
336
|
+
if (importer && sourceMap.has(importer)) {{
|
|
337
|
+
const originalSource = sourceMap.get(importer);
|
|
338
|
+
// Check for common issues like double slashes
|
|
339
|
+
if (source.includes('//') && !source.startsWith('http')) {{
|
|
340
|
+
this.error({{
|
|
341
|
+
message: `Cannot resolve "${{source}}" - path contains invalid double slash. Check your import in the original Jac file.`,
|
|
342
|
+
id: originalSource,
|
|
343
|
+
loc: {{ line: 1, column: 0 }}
|
|
344
|
+
}});
|
|
345
|
+
}}
|
|
346
|
+
}}
|
|
347
|
+
return null;
|
|
348
|
+
}}
|
|
349
|
+
}};
|
|
350
|
+
}}
|
|
351
|
+
|
|
310
352
|
/**
|
|
311
353
|
* Vite configuration generated from config.json (in project root)
|
|
312
354
|
* To customize, edit config.json instead of this file.
|
|
313
355
|
*/
|
|
314
356
|
|
|
315
357
|
export default defineConfig({{
|
|
316
|
-
plugins: [
|
|
358
|
+
plugins: [
|
|
359
|
+
jacSourceMapper(),{(newline + plugins_str + newline + ' ') if plugins_str else ''}],
|
|
317
360
|
root: buildDir, // base folder (.jac/client/) so vite can find node_modules
|
|
318
361
|
build: {{
|
|
362
|
+
sourcemap: true, // Enable source maps for better error messages
|
|
319
363
|
rollupOptions: {{
|
|
320
364
|
input: path.resolve(buildDir, "{entry_relative}"), // your compiled entry file
|
|
321
365
|
output: {{
|
|
322
366
|
entryFileNames: "client.[hash].js", // name of the final js file
|
|
323
367
|
assetFileNames: (assetInfo) => assetInfo.name?.endsWith('.css') ? 'styles.css' : '[name].[ext]',
|
|
368
|
+
sourcemapPathTransform: (relativeSourcePath) => {{
|
|
369
|
+
// Transform source map paths to point to original location
|
|
370
|
+
return relativeSourcePath;
|
|
371
|
+
}},
|
|
324
372
|
}},
|
|
325
373
|
}},
|
|
326
374
|
outDir: path.resolve(buildDir, "{output_relative}"), // final bundled output
|
|
@@ -330,7 +378,7 @@ export default defineConfig({{
|
|
|
330
378
|
publicDir: false,
|
|
331
379
|
{server_section} resolve: {{
|
|
332
380
|
alias: {{
|
|
333
|
-
"@jac
|
|
381
|
+
"@jac/runtime": path.resolve(buildDir, "{compiled_utils_relative}"),
|
|
334
382
|
"@jac-client/assets": path.resolve(buildDir, "{compiled_assets_relative}"),
|
|
335
383
|
}},
|
|
336
384
|
extensions: [{extensions_str}],
|
|
@@ -375,6 +423,14 @@ impl ViteBundler.find_bundle(self: ViteBundler) -> Optional[Path] {
|
|
|
375
423
|
|
|
376
424
|
"""Run Vite build with generated config in .jac/client/configs/."""
|
|
377
425
|
impl ViteBundler.build(self: ViteBundler, entry_file: Optional[Path] = None) -> None {
|
|
426
|
+
import sys;
|
|
427
|
+
import time;
|
|
428
|
+
import shutil;
|
|
429
|
+
import from jac_client.plugin.utils { ensure_bun_available }
|
|
430
|
+
# Ensure bun is available before proceeding
|
|
431
|
+
if not ensure_bun_available() {
|
|
432
|
+
raise ClientBundleError('Bun is required. Install manually: https://bun.sh') from None ;
|
|
433
|
+
}
|
|
378
434
|
self.output_dir.mkdir(parents=True, exist_ok=True);
|
|
379
435
|
generated_package_json = self._get_client_dir() / 'configs' / 'package.json';
|
|
380
436
|
if not generated_package_json.exists() {
|
|
@@ -387,7 +443,7 @@ impl ViteBundler.build(self: ViteBundler, entry_file: Optional[Path] = None) ->
|
|
|
387
443
|
build_dir = self._get_client_dir();
|
|
388
444
|
node_modules = build_dir / 'node_modules';
|
|
389
445
|
if not node_modules.exists() {
|
|
390
|
-
# Temporarily copy package.json to client build dir for
|
|
446
|
+
# Temporarily copy package.json to client build dir for bun install
|
|
391
447
|
build_package_json = build_dir / 'package.json';
|
|
392
448
|
configs_package_json = build_dir / 'configs' / 'package.json';
|
|
393
449
|
if configs_package_json.exists() and not build_package_json.exists() {
|
|
@@ -395,65 +451,78 @@ impl ViteBundler.build(self: ViteBundler, entry_file: Optional[Path] = None) ->
|
|
|
395
451
|
shutil.copy2(configs_package_json, build_package_json);
|
|
396
452
|
}
|
|
397
453
|
try {
|
|
398
|
-
# Install to .jac/client/node_modules
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
check=True
|
|
403
|
-
capture_output=True,
|
|
404
|
-
text=True
|
|
454
|
+
# Install to .jac/client/node_modules with progress feedback
|
|
455
|
+
print("\n ⏳ Installing dependencies...\n", flush=True);
|
|
456
|
+
start_time = time.time();
|
|
457
|
+
result = subprocess.run(
|
|
458
|
+
['bun', 'install'], cwd=build_dir, check=False, text=True
|
|
405
459
|
);
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
460
|
+
elapsed = time.time() - start_time;
|
|
461
|
+
if result.returncode != 0 {
|
|
462
|
+
print(
|
|
463
|
+
f"\n ✖ bun install failed after {elapsed:.1f}s",
|
|
464
|
+
file=sys.stderr
|
|
465
|
+
);
|
|
466
|
+
raise ClientBundleError("Failed to install dependencies") ;
|
|
467
|
+
}
|
|
468
|
+
print(f"\n ✔ Dependencies installed ({elapsed:.1f}s)", flush=True);
|
|
410
469
|
} except FileNotFoundError {
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
470
|
+
# This shouldn't happen since we check for bun at the start
|
|
471
|
+
raise ClientBundleError(
|
|
472
|
+
'Bun command not found. Install Bun: https://bun.sh'
|
|
473
|
+
) from None ;
|
|
414
474
|
}
|
|
415
475
|
}
|
|
416
476
|
if self.config_path {
|
|
417
477
|
# Make config path relative to build_dir (where vite runs from)
|
|
418
478
|
try {
|
|
419
479
|
config_rel = self.config_path.relative_to(build_dir);
|
|
420
|
-
command = ['
|
|
480
|
+
command = ['bun', 'x', 'vite', 'build', '--config', str(config_rel)];
|
|
421
481
|
} except ValueError {
|
|
422
482
|
# Config is outside client build dir, use absolute path
|
|
423
|
-
command = [
|
|
483
|
+
command = [
|
|
484
|
+
'bun',
|
|
485
|
+
'x',
|
|
486
|
+
'vite',
|
|
487
|
+
'build',
|
|
488
|
+
'--config',
|
|
489
|
+
str(self.config_path)
|
|
490
|
+
];
|
|
424
491
|
}
|
|
425
492
|
} elif entry_file {
|
|
426
493
|
generated_config = self.create_vite_config(entry_file);
|
|
427
494
|
# Config is in configs/, make it relative to build_dir
|
|
428
495
|
config_rel = generated_config.relative_to(build_dir);
|
|
429
|
-
command = ['
|
|
496
|
+
command = ['bun', 'x', 'vite', 'build', '--config', str(config_rel)];
|
|
430
497
|
} else {
|
|
431
|
-
command = ['
|
|
498
|
+
command = ['bun', 'run', 'build'];
|
|
432
499
|
}
|
|
433
500
|
# Run vite from client build directory so it can find node_modules
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
);
|
|
501
|
+
print("\n ⏳ Building client bundle...\n", flush=True);
|
|
502
|
+
start_time = time.time();
|
|
503
|
+
result = subprocess.run(command, cwd=build_dir, check=False, text=True);
|
|
504
|
+
elapsed = time.time() - start_time;
|
|
437
505
|
if result.returncode != 0 {
|
|
438
|
-
|
|
506
|
+
print(f"\n ✖ Vite build failed after {elapsed:.1f}s", file=sys.stderr);
|
|
439
507
|
raise ClientBundleError(
|
|
440
|
-
f"Vite build failed
|
|
508
|
+
f"Vite build failed (see output above)\nCommand: {' '.join(command)}"
|
|
441
509
|
) from None ;
|
|
442
510
|
}
|
|
511
|
+
print(f"\n ✔ Client bundle built ({elapsed:.1f}s)", flush=True);
|
|
443
512
|
} finally {
|
|
444
513
|
# Clean up temporary package.json in client build dir
|
|
445
514
|
build_package_json = build_dir / 'package.json';
|
|
446
515
|
if build_package_json.exists() {
|
|
447
516
|
build_package_json.unlink();
|
|
448
517
|
}
|
|
449
|
-
# Move
|
|
450
|
-
|
|
451
|
-
if
|
|
452
|
-
|
|
453
|
-
if
|
|
454
|
-
|
|
518
|
+
# Move bun.lockb to configs/ if it exists
|
|
519
|
+
build_bun_lockb = build_dir / 'bun.lockb';
|
|
520
|
+
if build_bun_lockb.exists() {
|
|
521
|
+
configs_bun_lockb = build_dir / 'configs' / 'bun.lockb';
|
|
522
|
+
if configs_bun_lockb.exists() {
|
|
523
|
+
configs_bun_lockb.unlink();
|
|
455
524
|
}
|
|
456
|
-
|
|
525
|
+
build_bun_lockb.rename(configs_bun_lockb);
|
|
457
526
|
}
|
|
458
527
|
}
|
|
459
528
|
}
|
|
@@ -521,6 +590,9 @@ export default defineConfig({{
|
|
|
521
590
|
plugins: [react()],
|
|
522
591
|
root: buildDir,
|
|
523
592
|
publicDir: false,
|
|
593
|
+
build: {{
|
|
594
|
+
sourcemap: true, // Enable source maps for better error messages
|
|
595
|
+
}},
|
|
524
596
|
server: {{
|
|
525
597
|
watch: {{
|
|
526
598
|
usePolling: true,
|
|
@@ -547,7 +619,7 @@ export default defineConfig({{
|
|
|
547
619
|
}},
|
|
548
620
|
resolve: {{
|
|
549
621
|
alias: {{
|
|
550
|
-
"@jac
|
|
622
|
+
"@jac/runtime": path.resolve(buildDir, "{compiled_utils_relative}"),
|
|
551
623
|
"@jac-client/assets": path.resolve(buildDir, "{compiled_assets_relative}"),
|
|
552
624
|
}},
|
|
553
625
|
extensions: [{extensions_str}],
|
|
@@ -558,8 +630,61 @@ export default defineConfig({{
|
|
|
558
630
|
return config_path;
|
|
559
631
|
}
|
|
560
632
|
|
|
633
|
+
"""Create config files from jac.toml [plugins.client.configs].
|
|
634
|
+
|
|
635
|
+
Generates JavaScript config files (e.g., postcss.config.js, tailwind.config.js)
|
|
636
|
+
from TOML configuration. Each key in [plugins.client.configs] becomes a config file.
|
|
637
|
+
|
|
638
|
+
Example jac.toml:
|
|
639
|
+
[plugins.client.configs.postcss]
|
|
640
|
+
plugins = ["tailwindcss", "autoprefixer"]
|
|
641
|
+
|
|
642
|
+
[plugins.client.configs.tailwind]
|
|
643
|
+
content = ["./src/**/*.{js,jsx}"]
|
|
644
|
+
|
|
645
|
+
This generates:
|
|
646
|
+
- .jac/client/configs/postcss.config.js
|
|
647
|
+
- .jac/client/configs/tailwind.config.js
|
|
648
|
+
"""
|
|
649
|
+
impl ViteBundler.create_config_files(self: ViteBundler) -> list[Path] {
|
|
650
|
+
configs = self.config_loader.get_configs();
|
|
651
|
+
if not configs {
|
|
652
|
+
return [];
|
|
653
|
+
}
|
|
654
|
+
build_dir = self._get_client_dir();
|
|
655
|
+
configs_dir = build_dir / 'configs';
|
|
656
|
+
configs_dir.mkdir(parents=True, exist_ok=True);
|
|
657
|
+
created_files: list[Path] = [];
|
|
658
|
+
for (config_name, config_data) in configs.items() {
|
|
659
|
+
config_path = configs_dir / f'{config_name}.config.js';
|
|
660
|
+
|
|
661
|
+
# Convert the TOML config to JavaScript module.exports
|
|
662
|
+
js_content = _toml_config_to_js(config_name, config_data);
|
|
663
|
+
config_path.write_text(js_content, encoding='utf-8');
|
|
664
|
+
created_files.append(config_path);
|
|
665
|
+
}
|
|
666
|
+
return created_files;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
"""Convert TOML config data to JavaScript config file content.
|
|
670
|
+
|
|
671
|
+
Generates a generic module.exports with the config data as JSON.
|
|
672
|
+
"""
|
|
673
|
+
def _toml_config_to_js(config_name: str, config_data: dict) -> str {
|
|
674
|
+
return f"module.exports = {json.dumps(config_data, indent=2)};\n";
|
|
675
|
+
}
|
|
676
|
+
|
|
561
677
|
"""Start Vite dev server as a subprocess."""
|
|
562
678
|
impl ViteBundler.start_dev_server(self: ViteBundler, port: int = 3000) -> Any {
|
|
679
|
+
import sys;
|
|
680
|
+
import time;
|
|
681
|
+
import from jac_client.plugin.utils { ensure_bun_available }
|
|
682
|
+
# Ensure bun is available before starting dev server
|
|
683
|
+
if not ensure_bun_available() {
|
|
684
|
+
raise ClientBundleError(
|
|
685
|
+
'Bun is required for dev server. Install manually: https://bun.sh'
|
|
686
|
+
) from None ;
|
|
687
|
+
}
|
|
563
688
|
build_dir = self._get_client_dir();
|
|
564
689
|
node_modules = build_dir / 'node_modules';
|
|
565
690
|
# Create/update index.html for dev server (load from compiled/ for HMR)
|
|
@@ -584,23 +709,25 @@ impl ViteBundler.start_dev_server(self: ViteBundler, port: int = 3000) -> Any {
|
|
|
584
709
|
if not generated_package_json.exists() {
|
|
585
710
|
self.create_package_json();
|
|
586
711
|
}
|
|
587
|
-
# Temporarily copy package.json for
|
|
712
|
+
# Temporarily copy package.json for bun install
|
|
588
713
|
build_package_json = build_dir / 'package.json';
|
|
589
714
|
if not build_package_json.exists() {
|
|
590
715
|
shutil.copy2(generated_package_json, build_package_json);
|
|
591
716
|
}
|
|
592
717
|
try {
|
|
593
|
-
print("
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
cwd=build_dir,
|
|
597
|
-
check=True,
|
|
598
|
-
capture_output=True,
|
|
599
|
-
text=True
|
|
718
|
+
print("\n ⏳ Installing dependencies...\n", flush=True);
|
|
719
|
+
start_time = time.time();
|
|
720
|
+
result = subprocess.run(
|
|
721
|
+
['bun', 'install'], cwd=build_dir, check=False, text=True
|
|
600
722
|
);
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
723
|
+
elapsed = time.time() - start_time;
|
|
724
|
+
if result.returncode != 0 {
|
|
725
|
+
print(
|
|
726
|
+
f"\n ✖ bun install failed after {elapsed:.1f}s", file=sys.stderr
|
|
727
|
+
);
|
|
728
|
+
raise ClientBundleError("Failed to install dependencies") ;
|
|
729
|
+
}
|
|
730
|
+
print(f"\n ✔ Dependencies installed ({elapsed:.1f}s)", flush=True);
|
|
604
731
|
} finally {
|
|
605
732
|
# Clean up temp package.json
|
|
606
733
|
if build_package_json.exists() {
|
|
@@ -616,10 +743,10 @@ impl ViteBundler.start_dev_server(self: ViteBundler, port: int = 3000) -> Any {
|
|
|
616
743
|
) ;
|
|
617
744
|
}
|
|
618
745
|
config_rel = dev_config.relative_to(build_dir);
|
|
619
|
-
|
|
746
|
+
logger.debug(f"Starting Vite dev server on port {port}");
|
|
620
747
|
# Start Vite in dev mode (let output go to terminal for HMR visibility)
|
|
621
748
|
process = subprocess.Popen(
|
|
622
|
-
['
|
|
749
|
+
['bun', 'x', 'vite', '--config', str(config_rel), '--port', str(port)],
|
|
623
750
|
cwd=build_dir
|
|
624
751
|
);
|
|
625
752
|
return process;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Jac Sidecar Entry Point
|
|
4
|
+
|
|
5
|
+
This is the entry point for the Jac backend sidecar.
|
|
6
|
+
It launches the Jac runtime and starts an HTTP API server.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
python -m jac_client.plugin.src.targets.desktop.sidecar.main [OPTIONS]
|
|
10
|
+
# Or via wrapper script: ./jac-sidecar.sh [OPTIONS]
|
|
11
|
+
|
|
12
|
+
Options:
|
|
13
|
+
--module-path PATH Path to the .jac module file (default: main.jac)
|
|
14
|
+
--port PORT Port to bind the API server (default: 8000)
|
|
15
|
+
--base-path PATH Base path for the project (default: current directory)
|
|
16
|
+
--host HOST Host to bind to (default: 127.0.0.1)
|
|
17
|
+
--help Show this help message
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import argparse
|
|
23
|
+
import sys
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
|
|
26
|
+
from jaclang.cli.console import console
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def main():
|
|
30
|
+
"""Main entry point for the sidecar."""
|
|
31
|
+
parser = argparse.ArgumentParser(
|
|
32
|
+
description="Jac Backend Sidecar - Runs Jac API server in a bundled executable"
|
|
33
|
+
)
|
|
34
|
+
parser.add_argument(
|
|
35
|
+
"--module-path",
|
|
36
|
+
type=str,
|
|
37
|
+
default="main.jac",
|
|
38
|
+
help="Path to the .jac module file (default: main.jac)",
|
|
39
|
+
)
|
|
40
|
+
parser.add_argument(
|
|
41
|
+
"--port",
|
|
42
|
+
type=int,
|
|
43
|
+
default=8000,
|
|
44
|
+
help="Port to bind the API server (default: 8000)",
|
|
45
|
+
)
|
|
46
|
+
parser.add_argument(
|
|
47
|
+
"--base-path",
|
|
48
|
+
type=str,
|
|
49
|
+
default=None,
|
|
50
|
+
help="Base path for the project (default: current directory)",
|
|
51
|
+
)
|
|
52
|
+
parser.add_argument(
|
|
53
|
+
"--host",
|
|
54
|
+
type=str,
|
|
55
|
+
default="127.0.0.1",
|
|
56
|
+
help="Host to bind to (default: 127.0.0.1)",
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
args = parser.parse_args()
|
|
60
|
+
|
|
61
|
+
# Determine base path
|
|
62
|
+
if args.base_path:
|
|
63
|
+
base_path = Path(args.base_path).resolve()
|
|
64
|
+
else:
|
|
65
|
+
# Try to find project root (look for jac.toml)
|
|
66
|
+
base_path = Path.cwd()
|
|
67
|
+
for parent in [base_path] + list(base_path.parents):
|
|
68
|
+
if (parent / "jac.toml").exists():
|
|
69
|
+
base_path = parent
|
|
70
|
+
break
|
|
71
|
+
|
|
72
|
+
# Resolve module path
|
|
73
|
+
module_path = Path(args.module_path)
|
|
74
|
+
if not module_path.is_absolute():
|
|
75
|
+
module_path = base_path / module_path
|
|
76
|
+
|
|
77
|
+
if not module_path.exists():
|
|
78
|
+
console.print(f"Error: Module file not found: {module_path}", file=sys.stderr)
|
|
79
|
+
console.print(f" Base path: {base_path}", file=sys.stderr)
|
|
80
|
+
sys.exit(1)
|
|
81
|
+
|
|
82
|
+
# Extract module name (without .jac extension)
|
|
83
|
+
module_name = module_path.stem
|
|
84
|
+
module_base = module_path.parent
|
|
85
|
+
|
|
86
|
+
# Import Jac runtime and server
|
|
87
|
+
try:
|
|
88
|
+
# Import jaclang (must be installed via pip)
|
|
89
|
+
from jaclang.pycore.runtime import JacRuntime as Jac
|
|
90
|
+
except ImportError as e:
|
|
91
|
+
console.print(f"Error: Failed to import Jac runtime: {e}", file=sys.stderr)
|
|
92
|
+
console.print(
|
|
93
|
+
" Make sure jaclang is installed: pip install jaclang", file=sys.stderr
|
|
94
|
+
)
|
|
95
|
+
sys.exit(1)
|
|
96
|
+
|
|
97
|
+
# Initialize Jac runtime
|
|
98
|
+
try:
|
|
99
|
+
# Import the module
|
|
100
|
+
Jac.jac_import(target=module_name, base_path=str(module_base), lng="jac")
|
|
101
|
+
if Jac.program.errors_had:
|
|
102
|
+
console.print("Error: Failed to compile module:", file=sys.stderr)
|
|
103
|
+
for error in Jac.program.errors_had:
|
|
104
|
+
console.print(f" {error}", file=sys.stderr)
|
|
105
|
+
sys.exit(1)
|
|
106
|
+
except Exception as e:
|
|
107
|
+
console.print(
|
|
108
|
+
f"Error: Failed to load module '{module_name}': {e}", file=sys.stderr
|
|
109
|
+
)
|
|
110
|
+
import traceback
|
|
111
|
+
|
|
112
|
+
traceback.print_exc()
|
|
113
|
+
sys.exit(1)
|
|
114
|
+
|
|
115
|
+
# Create and start the API server
|
|
116
|
+
try:
|
|
117
|
+
# Get server class (allows plugins like jac-scale to provide enhanced server)
|
|
118
|
+
server_class = Jac.get_api_server_class()
|
|
119
|
+
server = server_class(
|
|
120
|
+
module_name=module_name, port=args.port, base_path=str(base_path)
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
console.print("Jac Sidecar starting...")
|
|
124
|
+
console.print(f" Module: {module_name}")
|
|
125
|
+
console.print(f" Base path: {base_path}")
|
|
126
|
+
console.print(f" Server: http://{args.host}:{args.port}")
|
|
127
|
+
console.print("\nPress Ctrl+C to stop the server\n")
|
|
128
|
+
|
|
129
|
+
# Start the server (blocks until interrupted)
|
|
130
|
+
server.start(dev=False)
|
|
131
|
+
|
|
132
|
+
except KeyboardInterrupt:
|
|
133
|
+
console.print("\nShutting down sidecar...")
|
|
134
|
+
sys.exit(0)
|
|
135
|
+
except Exception as e:
|
|
136
|
+
console.print(f"Error: Server failed to start: {e}", file=sys.stderr)
|
|
137
|
+
import traceback
|
|
138
|
+
|
|
139
|
+
traceback.print_exc()
|
|
140
|
+
sys.exit(1)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
if __name__ == "__main__":
|
|
144
|
+
main()
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Desktop target implementation.
|
|
2
|
+
|
|
3
|
+
This target will be implemented in Phase 2.
|
|
4
|
+
"""
|
|
5
|
+
import from pathlib { Path }
|
|
6
|
+
import from typing { Optional }
|
|
7
|
+
import from jac_client.plugin.src.targets.registry { ClientTarget }
|
|
8
|
+
|
|
9
|
+
"""Desktop build target (placeholder for Phase 2)."""
|
|
10
|
+
class DesktopTarget(ClientTarget) {
|
|
11
|
+
def init(self: DesktopTarget) {
|
|
12
|
+
self.name = "desktop";
|
|
13
|
+
self.default = False;
|
|
14
|
+
self.requires_setup = True;
|
|
15
|
+
self.config_section = "desktop";
|
|
16
|
+
self.output_dir = Path("src-tauri/target/release/bundle");
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
"""Setup desktop target - scaffold Tauri project structure."""
|
|
20
|
+
override def setup(self: DesktopTarget, project_dir: Path) -> None;
|
|
21
|
+
|
|
22
|
+
"""Build desktop app - build web bundle first, then wrap with Tauri."""
|
|
23
|
+
override def build(
|
|
24
|
+
self: DesktopTarget,
|
|
25
|
+
entry_file: Path,
|
|
26
|
+
project_dir: Path,
|
|
27
|
+
platform: Optional[str] = None
|
|
28
|
+
) -> Path;
|
|
29
|
+
|
|
30
|
+
"""Start desktop dev server - start web dev server and launch tauri dev."""
|
|
31
|
+
override def dev(self: DesktopTarget, entry_file: Path, project_dir: Path) -> None;
|
|
32
|
+
|
|
33
|
+
"""Start desktop app - build web bundle and launch Tauri with built bundle."""
|
|
34
|
+
override def start(
|
|
35
|
+
self: DesktopTarget, entry_file: Path, project_dir: Path
|
|
36
|
+
) -> None;
|
|
37
|
+
}
|