jac-client 0.2.10__py3-none-any.whl → 0.2.12__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 +340 -371
- jac_client/examples/all-in-one/pages/BudgetPlanner.jac +19 -12
- jac_client/examples/all-in-one/pages/FeaturesTest.jac +31 -15
- jac_client/examples/all-in-one/pages/LandingPage.jac +113 -90
- jac_client/examples/all-in-one/pages/budget_planner_ui.cl.jac +34 -39
- jac_client/examples/all-in-one/pages/features_test_ui.cl.jac +464 -352
- jac_client/examples/all-in-one/pages/loginPage.jac +114 -119
- jac_client/examples/all-in-one/pages/nestedDemo.jac +43 -50
- jac_client/examples/all-in-one/pages/notFound.jac +14 -15
- 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 +77 -73
- jac_client/examples/asset-serving/image-asset/main.jac +47 -46
- jac_client/examples/asset-serving/import-alias/main.jac +93 -95
- jac_client/examples/basic/main.jac +17 -15
- jac_client/examples/basic-auth/main.jac +246 -254
- jac_client/examples/basic-auth-with-router/main.jac +272 -285
- jac_client/examples/basic-full-stack/main.jac +245 -242
- jac_client/examples/css-styling/js-styling/main.jac +41 -62
- jac_client/examples/css-styling/material-ui/main.jac +90 -90
- jac_client/examples/css-styling/pure-css/main.jac +35 -44
- jac_client/examples/css-styling/sass-example/main.jac +35 -44
- jac_client/examples/css-styling/styled-components/main.jac +38 -47
- jac_client/examples/css-styling/tailwind-example/main.jac +54 -43
- jac_client/examples/full-stack-with-auth/main.jac +407 -433
- jac_client/examples/little-x/main.jac +306 -344
- jac_client/examples/little-x/src/submit-button.jac +15 -14
- jac_client/examples/nested-folders/nested-advance/main.jac +18 -27
- 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/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 +26 -26
- jac_client/examples/with-router/main.jac +186 -223
- jac_client/plugin/client_runtime.cl.jac +5 -3
- jac_client/plugin/impl/client_runtime.impl.jac +1 -1
- jac_client/plugin/plugin_config.jac +53 -99
- jac_client/plugin/src/__init__.jac +0 -2
- jac_client/plugin/src/compiler.jac +0 -1
- jac_client/plugin/src/impl/compiler.impl.jac +49 -17
- 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 +146 -84
- jac_client/plugin/src/targets/impl/desktop_target.impl.jac +54 -41
- jac_client/plugin/utils/__init__.jac +3 -0
- jac_client/plugin/utils/bun_installer.jac +16 -0
- jac_client/plugin/utils/client_deps.jac +14 -0
- jac_client/plugin/utils/impl/bun_installer.impl.jac +99 -0
- jac_client/plugin/utils/impl/client_deps.impl.jac +73 -0
- jac_client/templates/client.jacpack +0 -4
- jac_client/templates/fullstack.jacpack +1 -5
- jac_client/tests/conftest.py +56 -41
- 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 +71 -6
- jac_client/tests/test_helpers.py +11 -18
- jac_client/tests/test_it.py +1 -1
- {jac_client-0.2.10.dist-info → jac_client-0.2.12.dist-info}/METADATA +5 -5
- jac_client-0.2.12.dist-info/RECORD +115 -0
- {jac_client-0.2.10.dist-info → jac_client-0.2.12.dist-info}/WHEEL +1 -1
- jac_client/plugin/src/babel_processor.jac +0 -18
- jac_client/plugin/src/impl/babel_processor.impl.jac +0 -89
- jac_client/plugin/utils/impl/node_installer.impl.jac +0 -249
- jac_client/plugin/utils/node_installer.jac +0 -41
- jac_client-0.2.10.dist-info/RECORD +0 -115
- {jac_client-0.2.10.dist-info → jac_client-0.2.12.dist-info}/entry_points.txt +0 -0
- {jac_client-0.2.10.dist-info → jac_client-0.2.12.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 (
|
|
@@ -131,22 +127,22 @@ impl ViteBundler.create_tsconfig(self: ViteBundler) -> Path {
|
|
|
131
127
|
}
|
|
132
128
|
|
|
133
129
|
"""
|
|
134
|
-
Clean up root package.json and move
|
|
130
|
+
Clean up root package.json and move bun.lockb to configs/.
|
|
135
131
|
|
|
136
|
-
Remove root package.json and move
|
|
132
|
+
Remove root package.json and move bun.lockb to configs/.
|
|
137
133
|
"""
|
|
138
134
|
impl ViteBundler._cleanup_root_package_files(self: ViteBundler) -> None {
|
|
139
135
|
root_package_json = self.project_dir / 'package.json';
|
|
140
|
-
|
|
136
|
+
root_bun_lockb = self.project_dir / 'bun.lockb';
|
|
141
137
|
build_dir = self._get_client_dir();
|
|
142
138
|
configs_dir = build_dir / 'configs';
|
|
143
|
-
|
|
144
|
-
if
|
|
139
|
+
configs_bun_lockb = configs_dir / 'bun.lockb';
|
|
140
|
+
if root_bun_lockb.exists() {
|
|
145
141
|
configs_dir.mkdir(exist_ok=True);
|
|
146
|
-
if
|
|
147
|
-
|
|
142
|
+
if configs_bun_lockb.exists() {
|
|
143
|
+
configs_bun_lockb.unlink();
|
|
148
144
|
}
|
|
149
|
-
shutil.move(str(
|
|
145
|
+
shutil.move(str(root_bun_lockb), str(configs_bun_lockb));
|
|
150
146
|
}
|
|
151
147
|
if root_package_json.exists() {
|
|
152
148
|
root_package_json.unlink();
|
|
@@ -154,7 +150,7 @@ impl ViteBundler._cleanup_root_package_files(self: ViteBundler) -> None {
|
|
|
154
150
|
}
|
|
155
151
|
|
|
156
152
|
"""
|
|
157
|
-
Ensure root package.json exists temporarily for
|
|
153
|
+
Ensure root package.json exists temporarily for bun commands.
|
|
158
154
|
|
|
159
155
|
Create root package.json temporarily if it doesn't exist.
|
|
160
156
|
"""
|
|
@@ -303,26 +299,76 @@ impl ViteBundler.create_vite_config(self: ViteBundler, entry_file: Path) -> Path
|
|
|
303
299
|
else '';
|
|
304
300
|
config_content = f'''import {{ defineConfig }} from "vite";
|
|
305
301
|
import path from "path";
|
|
302
|
+
import fs from "fs";
|
|
306
303
|
import {{ fileURLToPath }} from "url";
|
|
307
304
|
{imports_section}const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
308
305
|
// Config is in configs/ inside .jac/client/, so go up one level to .jac/client/, then up two more to project root
|
|
309
306
|
const buildDir = path.resolve(__dirname, "..");
|
|
310
307
|
const projectRoot = path.resolve(__dirname, "../../..");
|
|
311
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
|
+
|
|
312
352
|
/**
|
|
313
353
|
* Vite configuration generated from config.json (in project root)
|
|
314
354
|
* To customize, edit config.json instead of this file.
|
|
315
355
|
*/
|
|
316
356
|
|
|
317
357
|
export default defineConfig({{
|
|
318
|
-
plugins: [
|
|
358
|
+
plugins: [
|
|
359
|
+
jacSourceMapper(),{(newline + plugins_str + newline + ' ') if plugins_str else ''}],
|
|
319
360
|
root: buildDir, // base folder (.jac/client/) so vite can find node_modules
|
|
320
361
|
build: {{
|
|
362
|
+
sourcemap: true, // Enable source maps for better error messages
|
|
321
363
|
rollupOptions: {{
|
|
322
364
|
input: path.resolve(buildDir, "{entry_relative}"), // your compiled entry file
|
|
323
365
|
output: {{
|
|
324
366
|
entryFileNames: "client.[hash].js", // name of the final js file
|
|
325
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
|
+
}},
|
|
326
372
|
}},
|
|
327
373
|
}},
|
|
328
374
|
outDir: path.resolve(buildDir, "{output_relative}"), // final bundled output
|
|
@@ -332,7 +378,7 @@ export default defineConfig({{
|
|
|
332
378
|
publicDir: false,
|
|
333
379
|
{server_section} resolve: {{
|
|
334
380
|
alias: {{
|
|
335
|
-
"@jac
|
|
381
|
+
"@jac/runtime": path.resolve(buildDir, "{compiled_utils_relative}"),
|
|
336
382
|
"@jac-client/assets": path.resolve(buildDir, "{compiled_assets_relative}"),
|
|
337
383
|
}},
|
|
338
384
|
extensions: [{extensions_str}],
|
|
@@ -379,19 +425,32 @@ impl ViteBundler.find_bundle(self: ViteBundler) -> Optional[Path] {
|
|
|
379
425
|
impl ViteBundler.build(self: ViteBundler, entry_file: Optional[Path] = None) -> None {
|
|
380
426
|
import sys;
|
|
381
427
|
import time;
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
428
|
+
import shutil;
|
|
429
|
+
import from jac_client.plugin.utils { ensure_bun_available, ensure_client_deps }
|
|
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
|
+
}
|
|
434
|
+
# Ensure client npm deps are configured; prompt to install defaults if missing
|
|
435
|
+
if not ensure_client_deps(self.config_loader) {
|
|
436
|
+
raise ClientBundleError(
|
|
437
|
+
'Client dependencies not configured. Add [dependencies.npm] to jac.toml '
|
|
438
|
+
'or create a project with: jac create --use client'
|
|
439
|
+
) from None ;
|
|
389
440
|
}
|
|
441
|
+
self.output_dir.mkdir(parents=True, exist_ok=True);
|
|
442
|
+
# Always regenerate package.json to pick up any dependency changes
|
|
443
|
+
self.create_package_json();
|
|
390
444
|
try {
|
|
391
445
|
build_dir = self._get_client_dir();
|
|
392
446
|
node_modules = build_dir / 'node_modules';
|
|
447
|
+
# Reinstall if node_modules is missing or stale (e.g. empty from a prior failed install)
|
|
448
|
+
vite_bin = node_modules / '.bin' / 'vite';
|
|
449
|
+
if node_modules.exists() and not vite_bin.exists() {
|
|
450
|
+
shutil.rmtree(node_modules);
|
|
451
|
+
}
|
|
393
452
|
if not node_modules.exists() {
|
|
394
|
-
# Temporarily copy package.json to client build dir for
|
|
453
|
+
# Temporarily copy package.json to client build dir for bun install
|
|
395
454
|
build_package_json = build_dir / 'package.json';
|
|
396
455
|
configs_package_json = build_dir / 'configs' / 'package.json';
|
|
397
456
|
if configs_package_json.exists() and not build_package_json.exists() {
|
|
@@ -400,82 +459,82 @@ impl ViteBundler.build(self: ViteBundler, entry_file: Optional[Path] = None) ->
|
|
|
400
459
|
}
|
|
401
460
|
try {
|
|
402
461
|
# Install to .jac/client/node_modules with progress feedback
|
|
403
|
-
print(
|
|
404
|
-
" ⏳ Installing npm dependencies (this may take a minute)...",
|
|
405
|
-
flush=True
|
|
406
|
-
);
|
|
462
|
+
print("\n ⏳ Installing dependencies...\n", flush=True);
|
|
407
463
|
start_time = time.time();
|
|
408
464
|
result = subprocess.run(
|
|
409
|
-
['
|
|
465
|
+
['bun', 'install'],
|
|
410
466
|
cwd=build_dir,
|
|
411
467
|
check=False,
|
|
412
|
-
|
|
413
|
-
|
|
468
|
+
text=True,
|
|
469
|
+
capture_output=True
|
|
414
470
|
);
|
|
415
471
|
elapsed = time.time() - start_time;
|
|
416
472
|
if result.returncode != 0 {
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
);
|
|
421
|
-
raise ClientBundleError(
|
|
422
|
-
f"Failed to install npm dependencies: {result.stderr
|
|
423
|
-
or result.stdout}"
|
|
424
|
-
) ;
|
|
473
|
+
error_output = result.stderr or result.stdout;
|
|
474
|
+
error_msg = f"Dependency installation failed after {elapsed:.1f}s\n\n{error_output}\nCommand: bun install";
|
|
475
|
+
raise ClientBundleError(error_msg) from None ;
|
|
425
476
|
}
|
|
426
|
-
print(f" ✔ Dependencies installed ({elapsed:.1f}s)", flush=True);
|
|
477
|
+
print(f"\n ✔ Dependencies installed ({elapsed:.1f}s)", flush=True);
|
|
427
478
|
} except FileNotFoundError {
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
479
|
+
# This shouldn't happen since we check for bun at the start
|
|
480
|
+
raise ClientBundleError(
|
|
481
|
+
'Bun command not found. Install Bun: https://bun.sh'
|
|
482
|
+
) from None ;
|
|
431
483
|
}
|
|
432
484
|
}
|
|
433
485
|
if self.config_path {
|
|
434
486
|
# Make config path relative to build_dir (where vite runs from)
|
|
435
487
|
try {
|
|
436
488
|
config_rel = self.config_path.relative_to(build_dir);
|
|
437
|
-
command = ['
|
|
489
|
+
command = ['bun', 'x', 'vite', 'build', '--config', str(config_rel)];
|
|
438
490
|
} except ValueError {
|
|
439
491
|
# Config is outside client build dir, use absolute path
|
|
440
|
-
command = [
|
|
492
|
+
command = [
|
|
493
|
+
'bun',
|
|
494
|
+
'x',
|
|
495
|
+
'vite',
|
|
496
|
+
'build',
|
|
497
|
+
'--config',
|
|
498
|
+
str(self.config_path)
|
|
499
|
+
];
|
|
441
500
|
}
|
|
442
501
|
} elif entry_file {
|
|
443
502
|
generated_config = self.create_vite_config(entry_file);
|
|
444
503
|
# Config is in configs/, make it relative to build_dir
|
|
445
504
|
config_rel = generated_config.relative_to(build_dir);
|
|
446
|
-
command = ['
|
|
505
|
+
command = ['bun', 'x', 'vite', 'build', '--config', str(config_rel)];
|
|
447
506
|
} else {
|
|
448
|
-
command = ['
|
|
507
|
+
command = ['bun', 'run', 'build'];
|
|
449
508
|
}
|
|
450
509
|
# Run vite from client build directory so it can find node_modules
|
|
451
|
-
print(" ⏳ Building client bundle
|
|
510
|
+
print("\n ⏳ Building client bundle...\n", flush=True);
|
|
452
511
|
start_time = time.time();
|
|
453
512
|
result = subprocess.run(
|
|
454
|
-
command, cwd=build_dir, check=False,
|
|
513
|
+
command, cwd=build_dir, check=False, text=True, capture_output=True
|
|
455
514
|
);
|
|
456
515
|
elapsed = time.time() - start_time;
|
|
457
516
|
if result.returncode != 0 {
|
|
458
|
-
|
|
459
|
-
error_msg =
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
) from None ;
|
|
517
|
+
error_output = result.stderr or result.stdout;
|
|
518
|
+
error_msg = f"Vite build failed after {elapsed:.1f}s\n\n{error_output}\nCommand: {' '.join(
|
|
519
|
+
command
|
|
520
|
+
)}";
|
|
521
|
+
raise ClientBundleError(error_msg) from None ;
|
|
463
522
|
}
|
|
464
|
-
print(f" ✔ Client bundle built ({elapsed:.1f}s)", flush=True);
|
|
523
|
+
print(f"\n ✔ Client bundle built ({elapsed:.1f}s)", flush=True);
|
|
465
524
|
} finally {
|
|
466
525
|
# Clean up temporary package.json in client build dir
|
|
467
526
|
build_package_json = build_dir / 'package.json';
|
|
468
527
|
if build_package_json.exists() {
|
|
469
528
|
build_package_json.unlink();
|
|
470
529
|
}
|
|
471
|
-
# Move
|
|
472
|
-
|
|
473
|
-
if
|
|
474
|
-
|
|
475
|
-
if
|
|
476
|
-
|
|
530
|
+
# Move bun.lockb to configs/ if it exists
|
|
531
|
+
build_bun_lockb = build_dir / 'bun.lockb';
|
|
532
|
+
if build_bun_lockb.exists() {
|
|
533
|
+
configs_bun_lockb = build_dir / 'configs' / 'bun.lockb';
|
|
534
|
+
if configs_bun_lockb.exists() {
|
|
535
|
+
configs_bun_lockb.unlink();
|
|
477
536
|
}
|
|
478
|
-
|
|
537
|
+
build_bun_lockb.rename(configs_bun_lockb);
|
|
479
538
|
}
|
|
480
539
|
}
|
|
481
540
|
}
|
|
@@ -543,6 +602,9 @@ export default defineConfig({{
|
|
|
543
602
|
plugins: [react()],
|
|
544
603
|
root: buildDir,
|
|
545
604
|
publicDir: false,
|
|
605
|
+
build: {{
|
|
606
|
+
sourcemap: true, // Enable source maps for better error messages
|
|
607
|
+
}},
|
|
546
608
|
server: {{
|
|
547
609
|
watch: {{
|
|
548
610
|
usePolling: true,
|
|
@@ -565,11 +627,15 @@ export default defineConfig({{
|
|
|
565
627
|
target: "http://localhost:{api_port}",
|
|
566
628
|
changeOrigin: true,
|
|
567
629
|
}},
|
|
630
|
+
"/static": {{
|
|
631
|
+
target: "http://localhost:{api_port}",
|
|
632
|
+
changeOrigin: true,
|
|
633
|
+
}},
|
|
568
634
|
}},
|
|
569
635
|
}},
|
|
570
636
|
resolve: {{
|
|
571
637
|
alias: {{
|
|
572
|
-
"@jac
|
|
638
|
+
"@jac/runtime": path.resolve(buildDir, "{compiled_utils_relative}"),
|
|
573
639
|
"@jac-client/assets": path.resolve(buildDir, "{compiled_assets_relative}"),
|
|
574
640
|
}},
|
|
575
641
|
extensions: [{extensions_str}],
|
|
@@ -628,6 +694,13 @@ def _toml_config_to_js(config_name: str, config_data: dict) -> str {
|
|
|
628
694
|
impl ViteBundler.start_dev_server(self: ViteBundler, port: int = 3000) -> Any {
|
|
629
695
|
import sys;
|
|
630
696
|
import time;
|
|
697
|
+
import from jac_client.plugin.utils { ensure_bun_available }
|
|
698
|
+
# Ensure bun is available before starting dev server
|
|
699
|
+
if not ensure_bun_available() {
|
|
700
|
+
raise ClientBundleError(
|
|
701
|
+
'Bun is required for dev server. Install manually: https://bun.sh'
|
|
702
|
+
) from None ;
|
|
703
|
+
}
|
|
631
704
|
build_dir = self._get_client_dir();
|
|
632
705
|
node_modules = build_dir / 'node_modules';
|
|
633
706
|
# Create/update index.html for dev server (load from compiled/ for HMR)
|
|
@@ -652,36 +725,25 @@ impl ViteBundler.start_dev_server(self: ViteBundler, port: int = 3000) -> Any {
|
|
|
652
725
|
if not generated_package_json.exists() {
|
|
653
726
|
self.create_package_json();
|
|
654
727
|
}
|
|
655
|
-
# Temporarily copy package.json for
|
|
728
|
+
# Temporarily copy package.json for bun install
|
|
656
729
|
build_package_json = build_dir / 'package.json';
|
|
657
730
|
if not build_package_json.exists() {
|
|
658
731
|
shutil.copy2(generated_package_json, build_package_json);
|
|
659
732
|
}
|
|
660
733
|
try {
|
|
661
|
-
print(
|
|
662
|
-
" ⏳ Installing npm dependencies (this may take a minute)...",
|
|
663
|
-
flush=True
|
|
664
|
-
);
|
|
734
|
+
print("\n ⏳ Installing dependencies...\n", flush=True);
|
|
665
735
|
start_time = time.time();
|
|
666
736
|
result = subprocess.run(
|
|
667
|
-
['
|
|
668
|
-
cwd=build_dir,
|
|
669
|
-
check=False,
|
|
670
|
-
capture_output=True,
|
|
671
|
-
text=True
|
|
737
|
+
['bun', 'install'], cwd=build_dir, check=False, text=True
|
|
672
738
|
);
|
|
673
739
|
elapsed = time.time() - start_time;
|
|
674
740
|
if result.returncode != 0 {
|
|
675
741
|
print(
|
|
676
|
-
f"\n ✖
|
|
742
|
+
f"\n ✖ bun install failed after {elapsed:.1f}s", file=sys.stderr
|
|
677
743
|
);
|
|
678
|
-
|
|
679
|
-
raise ClientBundleError(
|
|
680
|
-
f"Failed to install npm dependencies: {result.stderr
|
|
681
|
-
or result.stdout}"
|
|
682
|
-
) ;
|
|
744
|
+
raise ClientBundleError("Failed to install dependencies") ;
|
|
683
745
|
}
|
|
684
|
-
print(f" ✔ Dependencies installed ({elapsed:.1f}s)", flush=True);
|
|
746
|
+
print(f"\n ✔ Dependencies installed ({elapsed:.1f}s)", flush=True);
|
|
685
747
|
} finally {
|
|
686
748
|
# Clean up temp package.json
|
|
687
749
|
if build_package_json.exists() {
|
|
@@ -700,7 +762,7 @@ impl ViteBundler.start_dev_server(self: ViteBundler, port: int = 3000) -> Any {
|
|
|
700
762
|
logger.debug(f"Starting Vite dev server on port {port}");
|
|
701
763
|
# Start Vite in dev mode (let output go to terminal for HMR visibility)
|
|
702
764
|
process = subprocess.Popen(
|
|
703
|
-
['
|
|
765
|
+
['bun', 'x', 'vite', '--config', str(config_rel), '--port', str(port)],
|
|
704
766
|
cwd=build_dir
|
|
705
767
|
);
|
|
706
768
|
return process;
|
|
@@ -1297,17 +1297,14 @@ def _check_and_install_tauri_cli -> None {
|
|
|
1297
1297
|
}
|
|
1298
1298
|
} except Exception { }
|
|
1299
1299
|
|
|
1300
|
-
# Check if
|
|
1301
|
-
|
|
1300
|
+
# Check if bun tauri CLI is available (global install)
|
|
1301
|
+
bun_tauri_ok = False;
|
|
1302
1302
|
try {
|
|
1303
1303
|
result = subprocess.run(
|
|
1304
|
-
["
|
|
1305
|
-
capture_output=True,
|
|
1306
|
-
text=True,
|
|
1307
|
-
timeout=5
|
|
1304
|
+
["bun", "pm", "ls", "-g"], capture_output=True, text=True, timeout=5
|
|
1308
1305
|
);
|
|
1309
|
-
if result.returncode == 0 {
|
|
1310
|
-
console.print(" ✔ Tauri CLI found (
|
|
1306
|
+
if result.returncode == 0 and "@tauri-apps/cli" in result.stdout {
|
|
1307
|
+
console.print(" ✔ Tauri CLI found (bun)", style="success");
|
|
1311
1308
|
return;
|
|
1312
1309
|
}
|
|
1313
1310
|
} except Exception { }
|
|
@@ -1327,22 +1324,22 @@ def _check_and_install_tauri_cli -> None {
|
|
|
1327
1324
|
cargo_available = True;
|
|
1328
1325
|
} except Exception { }
|
|
1329
1326
|
|
|
1330
|
-
# Check if
|
|
1331
|
-
|
|
1327
|
+
# Check if bun is available
|
|
1328
|
+
bun_available = False;
|
|
1332
1329
|
try {
|
|
1333
1330
|
subprocess.run(
|
|
1334
|
-
["
|
|
1331
|
+
["bun", "--version"], capture_output=True, check=True, timeout=5
|
|
1335
1332
|
);
|
|
1336
|
-
|
|
1333
|
+
bun_available = True;
|
|
1337
1334
|
} except Exception { }
|
|
1338
1335
|
|
|
1339
|
-
if not cargo_available and not
|
|
1336
|
+
if not cargo_available and not bun_available {
|
|
1340
1337
|
console.print(
|
|
1341
|
-
" Neither cargo nor
|
|
1338
|
+
" Neither cargo nor bun is available. Cannot install Tauri CLI automatically.",
|
|
1342
1339
|
style="muted"
|
|
1343
1340
|
);
|
|
1344
1341
|
console.print(
|
|
1345
|
-
" Please install Rust (for cargo) or
|
|
1342
|
+
" Please install Rust (for cargo) or Bun (https://bun.sh) first.",
|
|
1346
1343
|
style="muted"
|
|
1347
1344
|
);
|
|
1348
1345
|
return;
|
|
@@ -1371,11 +1368,11 @@ def _check_and_install_tauri_cli -> None {
|
|
|
1371
1368
|
console.warning(f" Error installing via cargo: {e}");
|
|
1372
1369
|
}
|
|
1373
1370
|
}
|
|
1374
|
-
if
|
|
1375
|
-
console.print(" Installing Tauri CLI via
|
|
1371
|
+
if bun_available {
|
|
1372
|
+
console.print(" Installing Tauri CLI via bun...", style="muted");
|
|
1376
1373
|
try {
|
|
1377
1374
|
result = subprocess.run(
|
|
1378
|
-
["
|
|
1375
|
+
["bun", "add", "-g", "@tauri-apps/cli"],
|
|
1379
1376
|
check=False,
|
|
1380
1377
|
timeout=300,
|
|
1381
1378
|
capture_output=False # Show output
|
|
@@ -1384,18 +1381,18 @@ def _check_and_install_tauri_cli -> None {
|
|
|
1384
1381
|
console.print(" ✔ Tauri CLI installed", style="success");
|
|
1385
1382
|
return;
|
|
1386
1383
|
} else {
|
|
1387
|
-
console.warning(" Failed to install via
|
|
1384
|
+
console.warning(" Failed to install via bun");
|
|
1388
1385
|
}
|
|
1389
1386
|
} except Exception as e {
|
|
1390
|
-
console.warning(f" Error installing via
|
|
1387
|
+
console.warning(f" Error installing via bun: {e}");
|
|
1391
1388
|
}
|
|
1392
1389
|
}
|
|
1393
1390
|
console.print(" Please install manually:", style="muted");
|
|
1394
1391
|
if cargo_available {
|
|
1395
1392
|
console.print(" cargo install tauri-cli", style="muted");
|
|
1396
1393
|
}
|
|
1397
|
-
if
|
|
1398
|
-
console.print("
|
|
1394
|
+
if bun_available {
|
|
1395
|
+
console.print(" bun add -g @tauri-apps/cli", style="muted");
|
|
1399
1396
|
}
|
|
1400
1397
|
} else {
|
|
1401
1398
|
console.print(" Skipping Tauri CLI installation.", style="muted");
|
|
@@ -1405,8 +1402,8 @@ def _check_and_install_tauri_cli -> None {
|
|
|
1405
1402
|
if cargo_available {
|
|
1406
1403
|
console.print(" cargo install tauri-cli", style="muted");
|
|
1407
1404
|
}
|
|
1408
|
-
if
|
|
1409
|
-
console.print("
|
|
1405
|
+
if bun_available {
|
|
1406
|
+
console.print(" bun add -g @tauri-apps/cli", style="muted");
|
|
1410
1407
|
}
|
|
1411
1408
|
}
|
|
1412
1409
|
}
|
|
@@ -1846,22 +1843,22 @@ def _run_tauri_build(tauri_dir: Path, platform: Optional[str] = None) -> Path {
|
|
|
1846
1843
|
target = "x86_64-unknown-linux-gnu";
|
|
1847
1844
|
}
|
|
1848
1845
|
|
|
1849
|
-
# Build command
|
|
1850
|
-
build_cmd = ["
|
|
1846
|
+
# Build command - prefer cargo tauri build, fallback to bun if package.json has tauri scripts
|
|
1847
|
+
build_cmd = ["cargo", "tauri", "build"];
|
|
1851
1848
|
if target {
|
|
1852
|
-
build_cmd.extend(["--",
|
|
1849
|
+
build_cmd.extend(["--target", target]);
|
|
1853
1850
|
}
|
|
1854
1851
|
|
|
1855
|
-
# Check if package.json has tauri scripts,
|
|
1852
|
+
# Check if package.json has tauri scripts, use bun run if so
|
|
1856
1853
|
package_json = tauri_dir.parent / "package.json";
|
|
1857
|
-
|
|
1854
|
+
use_bun = False;
|
|
1858
1855
|
if package_json.exists() {
|
|
1859
1856
|
try {
|
|
1860
1857
|
with open(package_json, "r") as f {
|
|
1861
1858
|
package_data = json.load(f);
|
|
1862
1859
|
scripts = package_data.get("scripts", {});
|
|
1863
1860
|
if "tauri" in scripts or "tauri:build" in scripts {
|
|
1864
|
-
|
|
1861
|
+
use_bun = True;
|
|
1865
1862
|
}
|
|
1866
1863
|
}
|
|
1867
1864
|
} except Exception {
|
|
@@ -1869,11 +1866,19 @@ def _run_tauri_build(tauri_dir: Path, platform: Optional[str] = None) -> Path {
|
|
|
1869
1866
|
}
|
|
1870
1867
|
}
|
|
1871
1868
|
|
|
1872
|
-
if
|
|
1873
|
-
#
|
|
1874
|
-
|
|
1869
|
+
if use_bun {
|
|
1870
|
+
# Ensure bun is available
|
|
1871
|
+
import from jac_client.plugin.utils { ensure_bun_available }
|
|
1872
|
+
if not ensure_bun_available() {
|
|
1873
|
+
console.error(
|
|
1874
|
+
"Bun is required for this project. Install manually: https://bun.sh"
|
|
1875
|
+
);
|
|
1876
|
+
raise RuntimeError("Bun is required") from None ;
|
|
1877
|
+
}
|
|
1878
|
+
# Use bun run tauri build
|
|
1879
|
+
build_cmd = ["bun", "run", "tauri", "build"];
|
|
1875
1880
|
if target {
|
|
1876
|
-
build_cmd.extend(["--
|
|
1881
|
+
build_cmd.extend(["--", "--target", target]);
|
|
1877
1882
|
}
|
|
1878
1883
|
}
|
|
1879
1884
|
|
|
@@ -2210,32 +2215,40 @@ def _run_tauri_dev(tauri_dir: Path) -> subprocess.Popen {
|
|
|
2210
2215
|
) {
|
|
2211
2216
|
console.warning("Tauri CLI not found.");
|
|
2212
2217
|
console.print(" Install manually: cargo install tauri-cli", style="muted");
|
|
2213
|
-
console.print(" Or use
|
|
2218
|
+
console.print(" Or use bun: bun add -g @tauri-apps/cli", style="muted");
|
|
2214
2219
|
raise RuntimeError(
|
|
2215
2220
|
"Tauri CLI not installed. Install it first:\n"
|
|
2216
2221
|
" cargo install tauri-cli\n"
|
|
2217
|
-
" Or:
|
|
2222
|
+
" Or: bun add -g @tauri-apps/cli"
|
|
2218
2223
|
) ;
|
|
2219
2224
|
}
|
|
2220
2225
|
|
|
2221
2226
|
# Check if package.json has tauri scripts
|
|
2222
2227
|
package_json = tauri_dir.parent / "package.json";
|
|
2223
|
-
|
|
2228
|
+
use_bun = False;
|
|
2224
2229
|
if package_json.exists() {
|
|
2225
2230
|
try {
|
|
2226
2231
|
with open(package_json, "r") as f {
|
|
2227
2232
|
package_data = json.load(f);
|
|
2228
2233
|
scripts = package_data.get("scripts", {});
|
|
2229
2234
|
if "tauri" in scripts or "tauri:dev" in scripts {
|
|
2230
|
-
|
|
2235
|
+
use_bun = True;
|
|
2231
2236
|
}
|
|
2232
2237
|
}
|
|
2233
2238
|
} except Exception { }
|
|
2234
2239
|
}
|
|
2235
2240
|
|
|
2236
|
-
if
|
|
2237
|
-
#
|
|
2238
|
-
|
|
2241
|
+
if use_bun {
|
|
2242
|
+
# Ensure bun is available
|
|
2243
|
+
import from jac_client.plugin.utils { ensure_bun_available }
|
|
2244
|
+
if not ensure_bun_available() {
|
|
2245
|
+
console.error(
|
|
2246
|
+
"Bun is required for this project. Install manually: https://bun.sh"
|
|
2247
|
+
);
|
|
2248
|
+
raise RuntimeError("Bun is required") from None ;
|
|
2249
|
+
}
|
|
2250
|
+
# Use bun run tauri dev
|
|
2251
|
+
dev_cmd = ["bun", "run", "tauri", "dev"];
|
|
2239
2252
|
} else {
|
|
2240
2253
|
# Use cargo tauri dev directly
|
|
2241
2254
|
dev_cmd = ["cargo", "tauri", "dev"];
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""Bun installer utility for jac-client.
|
|
2
|
+
|
|
3
|
+
Provides functions to check for Bun availability and prompt for installation.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
"""Check if bun is available, add to PATH if needed, or prompt to install.
|
|
7
|
+
|
|
8
|
+
Returns True if bun is available (or was successfully installed), False otherwise.
|
|
9
|
+
"""
|
|
10
|
+
def ensure_bun_available -> bool;
|
|
11
|
+
|
|
12
|
+
"""Prompt user to install Bun and install if confirmed.
|
|
13
|
+
|
|
14
|
+
Returns True if installation succeeded, False otherwise.
|
|
15
|
+
"""
|
|
16
|
+
def prompt_install_bun -> bool;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Client dependency checker utility for jac-client.
|
|
2
|
+
|
|
3
|
+
Provides a function to check if required npm dependencies are configured
|
|
4
|
+
and prompt the user to install defaults if missing.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
"""Check if client npm dependencies are configured, prompt to install if missing.
|
|
8
|
+
|
|
9
|
+
Takes a JacClientConfig instance, checks if dependencies and devDependencies
|
|
10
|
+
are both empty, and if so prompts the user to install default jac-client deps.
|
|
11
|
+
|
|
12
|
+
Returns True if deps are configured (or were just installed), False if user declined.
|
|
13
|
+
"""
|
|
14
|
+
def ensure_client_deps(config_loader: object) -> bool;
|