juxscript 1.1.92 → 1.1.93
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.
- package/dom-structure-map.json +1 -1
- package/machinery/compiler3.js +83 -347
- package/package.json +1 -1
package/dom-structure-map.json
CHANGED
package/machinery/compiler3.js
CHANGED
|
@@ -202,180 +202,6 @@ export class JuxCompiler {
|
|
|
202
202
|
return issues;
|
|
203
203
|
}
|
|
204
204
|
|
|
205
|
-
/**
|
|
206
|
-
* ✅ Generate routes based on folder structure
|
|
207
|
-
*/
|
|
208
|
-
_generateRouter(views) {
|
|
209
|
-
let routeMap = '';
|
|
210
|
-
|
|
211
|
-
views.forEach(v => {
|
|
212
|
-
// ✅ Generate route from folder structure
|
|
213
|
-
// abc/juxabc.jux -> /abc/juxabc
|
|
214
|
-
// index.jux -> /
|
|
215
|
-
// abc/index.jux -> /abc
|
|
216
|
-
|
|
217
|
-
const routePath = this._generateRoutePath(v.file);
|
|
218
|
-
const functionName = this._generateFunctionName(v.name);
|
|
219
|
-
|
|
220
|
-
routeMap += ` '${routePath}': render${functionName},\n`;
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
return `
|
|
224
|
-
// --- JUX SOURCE LOADER ---
|
|
225
|
-
var __juxSources = null;
|
|
226
|
-
async function __juxLoadSources() {
|
|
227
|
-
if (__juxSources) return __juxSources;
|
|
228
|
-
try {
|
|
229
|
-
var res = await fetch('/__jux_sources.json');
|
|
230
|
-
__juxSources = await res.json();
|
|
231
|
-
} catch (e) {
|
|
232
|
-
__juxSources = {};
|
|
233
|
-
}
|
|
234
|
-
return __juxSources;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
function __juxFindSource(stack) {
|
|
238
|
-
var match = stack.match(/render([A-Z][a-zA-Z0-9_]*)/);
|
|
239
|
-
if (match) {
|
|
240
|
-
var funcName = match[1];
|
|
241
|
-
for (var file in __juxSources || {}) {
|
|
242
|
-
var normalized = __juxSources[file].name
|
|
243
|
-
.split('_')
|
|
244
|
-
.map(s => s.charAt(0).toUpperCase() + s.slice(1).toLowerCase())
|
|
245
|
-
.join('');
|
|
246
|
-
|
|
247
|
-
if (normalized === funcName) {
|
|
248
|
-
return { file: file, source: __juxSources[file], viewName: funcName };
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
return null;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
// --- JUX RUNTIME ERROR OVERLAY ---
|
|
256
|
-
var __juxErrorOverlay = {
|
|
257
|
-
styles: \`
|
|
258
|
-
#__jux-error-overlay {
|
|
259
|
-
position: fixed; inset: 0; z-index: 99999;
|
|
260
|
-
background: rgba(0, 0, 0, 0.4);
|
|
261
|
-
display: flex; align-items: center; justify-content: center;
|
|
262
|
-
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
|
|
263
|
-
opacity: 0; transition: opacity 0.2s ease-out; backdrop-filter: blur(2px);
|
|
264
|
-
}
|
|
265
|
-
#__jux-error-overlay.visible { opacity: 1; }
|
|
266
|
-
#__jux-error-overlay * { box-sizing: border-box; }
|
|
267
|
-
.__jux-modal {
|
|
268
|
-
background: #f8f9fa; border-radius: 4px;
|
|
269
|
-
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.4);
|
|
270
|
-
max-width: 80vw; width: 90%; max-height: 90vh;
|
|
271
|
-
overflow: hidden; display: flex; flex-direction: column;
|
|
272
|
-
transform: translateY(10px); transition: transform 0.2s ease-out;
|
|
273
|
-
}
|
|
274
|
-
#__jux-error-overlay.visible .__jux-modal { transform: translateY(0); }
|
|
275
|
-
.__jux-header { background: #fff; padding: 20px 24px; border-bottom: 1px solid #e5e7eb; }
|
|
276
|
-
.__jux-header h3 { margin: 0 0 6px; font-weight: 600; font-size: 11px; color: #9ca3af; text-transform: uppercase; }
|
|
277
|
-
.__jux-header h1 { margin: 0 0 8px; font-size: 18px; font-weight: 600; color: #dc2626; line-height: 1.3; }
|
|
278
|
-
.__jux-header .file-info { color: #6b7280; font-size: 13px; }
|
|
279
|
-
.__jux-header .file-info strong { color: #dc2626; font-weight: 600; }
|
|
280
|
-
.__jux-source { padding: 16px 24px; overflow: auto; flex: 1; background: #f8f9fa; }
|
|
281
|
-
.__jux-code { background: #fff; border-radius: 8px; overflow: hidden; border: 1px solid #e5e7eb; }
|
|
282
|
-
.__jux-code-line { display: flex; font-size: 13px; line-height: 1.7; }
|
|
283
|
-
.__jux-code-line.error { background: #fef2f2; }
|
|
284
|
-
.__jux-code-line.error .__jux-line-code { color: #dc2626; font-weight: 500; }
|
|
285
|
-
.__jux-code-line.context { background: #fefce8; }
|
|
286
|
-
.__jux-line-num { min-width: 44px; padding: 4px 12px; text-align: right; color: #9ca3af; background: #f9fafb; border-right: 1px solid #e5e7eb; font-size: 12px; }
|
|
287
|
-
.__jux-code-line.error .__jux-line-num { background: #fef2f2; color: #dc2626; }
|
|
288
|
-
.__jux-line-code { flex: 1; padding: 4px 16px; color: #374151; white-space: pre; overflow-x: auto; }
|
|
289
|
-
.__jux-footer { padding: 16px 24px; background: #fff; border-top: 1px solid #e5e7eb; display: flex; justify-content: space-between; align-items: center; }
|
|
290
|
-
.__jux-tip { color: #6b7280; font-size: 12px; }
|
|
291
|
-
.__jux-dismiss { background: #f3f4f6; color: #374151; border: 1px solid #d1d5db; padding: 8px 16px; border-radius: 6px; cursor: pointer; font-size: 13px; font-weight: 500; }
|
|
292
|
-
.__jux-dismiss:hover { background: #e5e7eb; }
|
|
293
|
-
.__jux-no-source { color: #6b7280; padding: 24px; text-align: center; }
|
|
294
|
-
.__jux-no-source pre { background: #fff; padding: 16px; border-radius: 8px; margin-top: 16px; font-size: 11px; color: #6b7280; overflow-x: auto; text-align: left; border: 1px solid #e5e7eb; }
|
|
295
|
-
\`,
|
|
296
|
-
|
|
297
|
-
show: async function(error, title) {
|
|
298
|
-
title = title || 'Runtime Error';
|
|
299
|
-
var existing = document.getElementById('__jux-error-overlay');
|
|
300
|
-
if (existing) existing.remove();
|
|
301
|
-
await __juxLoadSources();
|
|
302
|
-
|
|
303
|
-
var overlay = document.createElement('div');
|
|
304
|
-
overlay.id = '__jux-error-overlay';
|
|
305
|
-
var stack = error && error.stack ? error.stack : '';
|
|
306
|
-
var msg = error && error.message ? error.message : String(error);
|
|
307
|
-
var found = __juxFindSource(stack);
|
|
308
|
-
var sourceHtml = '', fileInfo = '';
|
|
309
|
-
|
|
310
|
-
if (found && found.source && found.source.lines) {
|
|
311
|
-
var lines = found.source.lines;
|
|
312
|
-
fileInfo = '<span class="file-info">in <strong>' + found.file + '</strong></span>';
|
|
313
|
-
var errorLineIndex = -1;
|
|
314
|
-
var errorMethod = msg.match(/\\.([a-zA-Z]+)\\s*is not a function/);
|
|
315
|
-
if (errorMethod) {
|
|
316
|
-
for (var i = 0; i < lines.length; i++) {
|
|
317
|
-
if (lines[i].indexOf('.' + errorMethod[1]) > -1) { errorLineIndex = i; break; }
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
if (errorLineIndex === -1) {
|
|
321
|
-
for (var i = 0; i < lines.length; i++) {
|
|
322
|
-
if (lines[i].indexOf('throw ') > -1) { errorLineIndex = i; break; }
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
var contextStart = Math.max(0, errorLineIndex - 3);
|
|
326
|
-
var contextEnd = Math.min(lines.length - 1, errorLineIndex + 5);
|
|
327
|
-
if (errorLineIndex === -1) { contextStart = 0; contextEnd = Math.min(14, lines.length - 1); }
|
|
328
|
-
|
|
329
|
-
for (var i = contextStart; i <= contextEnd; i++) {
|
|
330
|
-
var isError = (i === errorLineIndex);
|
|
331
|
-
var isContext = !isError && errorLineIndex > -1 && Math.abs(i - errorLineIndex) <= 2;
|
|
332
|
-
var lineClass = isError ? ' error' : (isContext ? ' context' : '');
|
|
333
|
-
var lineCode = lines[i].replace(/</g, '<').replace(/>/g, '>') || ' ';
|
|
334
|
-
sourceHtml += '<div class="__jux-code-line' + lineClass + '"><span class="__jux-line-num">' + (i + 1) + '</span><span class="__jux-line-code">' + lineCode + '</span></div>';
|
|
335
|
-
}
|
|
336
|
-
} else {
|
|
337
|
-
sourceHtml = '<div class="__jux-no-source"><p>Could not locate source file.</p><pre>' + stack + '</pre></div>';
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
overlay.innerHTML = '<style>' + this.styles + '</style><div class="__jux-modal"><div class="__jux-header"><h3>' + title + '</h3><h1>' + msg + '</h1>' + fileInfo + '</div><div class="__jux-source"><div class="__jux-code">' + sourceHtml + '</div></div><div class="__jux-footer"><span class="__jux-tip">💡 Fix the error and save to reload</span><button class="__jux-dismiss" onclick="document.getElementById(\\'__jux-error-overlay\\').remove()">Dismiss</button></div></div>';
|
|
341
|
-
document.body.appendChild(overlay);
|
|
342
|
-
requestAnimationFrame(function() { overlay.classList.add('visible'); });
|
|
343
|
-
console.error(title + ':', error);
|
|
344
|
-
}
|
|
345
|
-
};
|
|
346
|
-
|
|
347
|
-
window.addEventListener('error', function(e) { __juxErrorOverlay.show(e.error || new Error(e.message), 'Uncaught Error'); }, true);
|
|
348
|
-
window.addEventListener('unhandledrejection', function(e) { __juxErrorOverlay.show(e.reason || new Error('Promise rejected'), 'Unhandled Promise Rejection'); }, true);
|
|
349
|
-
|
|
350
|
-
// --- JUX ROUTER ---
|
|
351
|
-
const routes = {\n${routeMap}};
|
|
352
|
-
|
|
353
|
-
async function navigate(path) {
|
|
354
|
-
const view = routes[path];
|
|
355
|
-
if (!view) {
|
|
356
|
-
document.getElementById('app').innerHTML = '<h1 style="padding:40px;">404 - Not Found</h1>';
|
|
357
|
-
return;
|
|
358
|
-
}
|
|
359
|
-
document.getElementById('app').innerHTML = '';
|
|
360
|
-
var overlay = document.getElementById('__jux-error-overlay');
|
|
361
|
-
if (overlay) overlay.remove();
|
|
362
|
-
try { await view(); } catch (err) { __juxErrorOverlay.show(err, 'Jux Render Error'); }
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
document.addEventListener('click', e => {
|
|
366
|
-
const a = e.target.closest('a');
|
|
367
|
-
if (!a || a.dataset.router === 'false') return;
|
|
368
|
-
try { if (new URL(a.href, location.origin).origin !== location.origin) return; } catch { return; }
|
|
369
|
-
e.preventDefault();
|
|
370
|
-
history.pushState({}, '', a.href);
|
|
371
|
-
navigate(new URL(a.href, location.origin).pathname);
|
|
372
|
-
});
|
|
373
|
-
|
|
374
|
-
window.addEventListener('popstate', () => navigate(location.pathname));
|
|
375
|
-
navigate(location.pathname);
|
|
376
|
-
`;
|
|
377
|
-
}
|
|
378
|
-
|
|
379
205
|
/**
|
|
380
206
|
* ✅ Generate route path from file path
|
|
381
207
|
* Examples:
|
|
@@ -484,191 +310,101 @@ navigate(location.pathname);
|
|
|
484
310
|
}
|
|
485
311
|
|
|
486
312
|
reportValidationIssues() {
|
|
487
|
-
|
|
488
|
-
const errors = issues.filter(i => i.type === 'error');
|
|
489
|
-
const warnings = issues.filter(i => i.type === 'warning');
|
|
490
|
-
|
|
491
|
-
if (issues.length > 0) {
|
|
492
|
-
console.log('\n⚠️ Validation Issues:\n');
|
|
493
|
-
issues.forEach(issue => {
|
|
494
|
-
const icon = issue.type === 'error' ? '❌' : '⚠️';
|
|
495
|
-
console.log(`${icon} [${issue.view}:${issue.line}] ${issue.message}`);
|
|
496
|
-
});
|
|
497
|
-
console.log('');
|
|
498
|
-
}
|
|
313
|
+
if (!this._validationIssues || this._validationIssues.length === 0) return;
|
|
499
314
|
|
|
500
|
-
|
|
315
|
+
console.log('\n⚠️ Validation Issues:\n');
|
|
316
|
+
this._validationIssues.forEach(issue => {
|
|
317
|
+
const icon = issue.type === 'error' ? '❌' : '⚠️';
|
|
318
|
+
console.log(` ${icon} ${issue.view}:${issue.line} - ${issue.message}`);
|
|
319
|
+
});
|
|
320
|
+
console.log('');
|
|
501
321
|
}
|
|
502
322
|
|
|
503
|
-
|
|
504
|
-
|
|
323
|
+
/**
|
|
324
|
+
* ✅ Build method - INSIDE the class
|
|
325
|
+
*/
|
|
326
|
+
async build() {
|
|
327
|
+
console.log('🔨 Building JUX application...\n');
|
|
505
328
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
// abc/juxabc.jux -> /abc/juxabc
|
|
509
|
-
// index.jux -> /
|
|
510
|
-
// abc/index.jux -> /abc
|
|
329
|
+
try {
|
|
330
|
+
const startTime = Date.now();
|
|
511
331
|
|
|
512
|
-
|
|
513
|
-
const
|
|
332
|
+
// Scan files
|
|
333
|
+
const { views, dataModules, sharedModules } = this.scanFiles();
|
|
514
334
|
|
|
515
|
-
|
|
516
|
-
});
|
|
335
|
+
console.log(`📂 Found ${views.length} views, ${dataModules.length} data modules, ${sharedModules.length} shared modules\n`);
|
|
517
336
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
var __juxSources = null;
|
|
521
|
-
async function __juxLoadSources() {
|
|
522
|
-
if (__juxSources) return __juxSources;
|
|
523
|
-
try {
|
|
524
|
-
var res = await fetch('/__jux_sources.json');
|
|
525
|
-
__juxSources = await res.json();
|
|
526
|
-
} catch (e) {
|
|
527
|
-
__juxSources = {};
|
|
528
|
-
}
|
|
529
|
-
return __juxSources;
|
|
530
|
-
}
|
|
337
|
+
// Load juxscript exports for validation
|
|
338
|
+
await this.loadJuxscriptExports();
|
|
531
339
|
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
var funcName = match[1];
|
|
536
|
-
for (var file in __juxSources || {}) {
|
|
537
|
-
var normalized = __juxSources[file].name
|
|
538
|
-
.split('_')
|
|
539
|
-
.map(s => s.charAt(0).toUpperCase() + s.slice(1).toLowerCase())
|
|
540
|
-
.join('');
|
|
541
|
-
|
|
542
|
-
if (normalized === funcName) {
|
|
543
|
-
return { file: file, source: __juxSources[file], viewName: funcName };
|
|
340
|
+
// Ensure dist directory exists
|
|
341
|
+
if (!fs.existsSync(this.distDir)) {
|
|
342
|
+
fs.mkdirSync(this.distDir, { recursive: true });
|
|
544
343
|
}
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
return null;
|
|
548
|
-
}
|
|
549
344
|
|
|
550
|
-
//
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
transform: translateY(10px); transition: transform 0.2s ease-out;
|
|
568
|
-
}
|
|
569
|
-
#__jux-error-overlay.visible .__jux-modal { transform: translateY(0); }
|
|
570
|
-
.__jux-header { background: #fff; padding: 20px 24px; border-bottom: 1px solid #e5e7eb; }
|
|
571
|
-
.__jux-header h3 { margin: 0 0 6px; font-weight: 600; font-size: 11px; color: #9ca3af; text-transform: uppercase; }
|
|
572
|
-
.__jux-header h1 { margin: 0 0 8px; font-size: 18px; font-weight: 600; color: #dc2626; line-height: 1.3; }
|
|
573
|
-
.__jux-header .file-info { color: #6b7280; font-size: 13px; }
|
|
574
|
-
.__jux-header .file-info strong { color: #dc2626; font-weight: 600; }
|
|
575
|
-
.__jux-source { padding: 16px 24px; overflow: auto; flex: 1; background: #f8f9fa; }
|
|
576
|
-
.__jux-code { background: #fff; border-radius: 8px; overflow: hidden; border: 1px solid #e5e7eb; }
|
|
577
|
-
.__jux-code-line { display: flex; font-size: 13px; line-height: 1.7; }
|
|
578
|
-
.__jux-code-line.error { background: #fef2f2; }
|
|
579
|
-
.__jux-code-line.error .__jux-line-code { color: #dc2626; font-weight: 500; }
|
|
580
|
-
.__jux-code-line.context { background: #fefce8; }
|
|
581
|
-
.__jux-line-num { min-width: 44px; padding: 4px 12px; text-align: right; color: #9ca3af; background: #f9fafb; border-right: 1px solid #e5e7eb; font-size: 12px; }
|
|
582
|
-
.__jux-code-line.error .__jux-line-num { background: #fef2f2; color: #dc2626; }
|
|
583
|
-
.__jux-line-code { flex: 1; padding: 4px 16px; color: #374151; white-space: pre; overflow-x: auto; }
|
|
584
|
-
.__jux-footer { padding: 16px 24px; background: #fff; border-top: 1px solid #e5e7eb; display: flex; justify-content: space-between; align-items: center; }
|
|
585
|
-
.__jux-tip { color: #6b7280; font-size: 12px; }
|
|
586
|
-
.__jux-dismiss { background: #f3f4f6; color: #374151; border: 1px solid #d1d5db; padding: 8px 16px; border-radius: 6px; cursor: pointer; font-size: 13px; font-weight: 500; }
|
|
587
|
-
.__jux-dismiss:hover { background: #e5e7eb; }
|
|
588
|
-
.__jux-no-source { color: #6b7280; padding: 24px; text-align: center; }
|
|
589
|
-
.__jux-no-source pre { background: #fff; padding: 16px; border-radius: 8px; margin-top: 16px; font-size: 11px; color: #6b7280; overflow-x: auto; text-align: left; border: 1px solid #e5e7eb; }
|
|
590
|
-
\`,
|
|
591
|
-
|
|
592
|
-
show: async function(error, title) {
|
|
593
|
-
title = title || 'Runtime Error';
|
|
594
|
-
var existing = document.getElementById('__jux-error-overlay');
|
|
595
|
-
if (existing) existing.remove();
|
|
596
|
-
await __juxLoadSources();
|
|
597
|
-
|
|
598
|
-
var overlay = document.createElement('div');
|
|
599
|
-
overlay.id = '__jux-error-overlay';
|
|
600
|
-
var stack = error && error.stack ? error.stack : '';
|
|
601
|
-
var msg = error && error.message ? error.message : String(error);
|
|
602
|
-
var found = __juxFindSource(stack);
|
|
603
|
-
var sourceHtml = '', fileInfo = '';
|
|
604
|
-
|
|
605
|
-
if (found && found.source && found.source.lines) {
|
|
606
|
-
var lines = found.source.lines;
|
|
607
|
-
fileInfo = '<span class="file-info">in <strong>' + found.file + '</strong></span>';
|
|
608
|
-
var errorLineIndex = -1;
|
|
609
|
-
var errorMethod = msg.match(/\\.([a-zA-Z]+)\\s*is not a function/);
|
|
610
|
-
if (errorMethod) {
|
|
611
|
-
for (var i = 0; i < lines.length; i++) {
|
|
612
|
-
if (lines[i].indexOf('.' + errorMethod[1]) > -1) { errorLineIndex = i; break; }
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
if (errorLineIndex === -1) {
|
|
616
|
-
for (var i = 0; i < lines.length; i++) {
|
|
617
|
-
if (lines[i].indexOf('throw ') > -1) { errorLineIndex = i; break; }
|
|
618
|
-
}
|
|
619
|
-
}
|
|
620
|
-
var contextStart = Math.max(0, errorLineIndex - 3);
|
|
621
|
-
var contextEnd = Math.min(lines.length - 1, errorLineIndex + 5);
|
|
622
|
-
if (errorLineIndex === -1) { contextStart = 0; contextEnd = Math.min(14, lines.length - 1); }
|
|
623
|
-
|
|
624
|
-
for (var i = contextStart; i <= contextEnd; i++) {
|
|
625
|
-
var isError = (i === errorLineIndex);
|
|
626
|
-
var isContext = !isError && errorLineIndex > -1 && Math.abs(i - errorLineIndex) <= 2;
|
|
627
|
-
var lineClass = isError ? ' error' : (isContext ? ' context' : '');
|
|
628
|
-
var lineCode = lines[i].replace(/</g, '<').replace(/>/g, '>') || ' ';
|
|
629
|
-
sourceHtml += '<div class="__jux-code-line' + lineClass + '"><span class="__jux-line-num">' + (i + 1) + '</span><span class="__jux-line-code">' + lineCode + '</span></div>';
|
|
630
|
-
}
|
|
631
|
-
} else {
|
|
632
|
-
sourceHtml = '<div class="__jux-no-source"><p>Could not locate source file.</p><pre>' + stack + '</pre></div>';
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
overlay.innerHTML = '<style>' + this.styles + '</style><div class="__jux-modal"><div class="__jux-header"><h3>' + title + '</h3><h1>' + msg + '</h1>' + fileInfo + '</div><div class="__jux-source"><div class="__jux-code">' + sourceHtml + '</div></div><div class="__jux-footer"><span class="__jux-tip">💡 Fix the error and save to reload</span><button class="__jux-dismiss" onclick="document.getElementById(\\'__jux-error-overlay\\').remove()">Dismiss</button></div></div>';
|
|
636
|
-
document.body.appendChild(overlay);
|
|
637
|
-
requestAnimationFrame(function() { overlay.classList.add('visible'); });
|
|
638
|
-
console.error(title + ':', error);
|
|
639
|
-
}
|
|
640
|
-
};
|
|
641
|
-
|
|
642
|
-
window.addEventListener('error', function(e) { __juxErrorOverlay.show(e.error || new Error(e.message), 'Uncaught Error'); }, true);
|
|
643
|
-
window.addEventListener('unhandledrejection', function(e) { __juxErrorOverlay.show(e.reason || new Error('Promise rejected'), 'Unhandled Promise Rejection'); }, true);
|
|
644
|
-
|
|
645
|
-
// --- JUX ROUTER ---
|
|
646
|
-
const routes = {\n${routeMap}};
|
|
345
|
+
// Generate entry point
|
|
346
|
+
const entryCode = this.generateEntryPoint(views, dataModules, sharedModules);
|
|
347
|
+
const entryPath = path.join(this.distDir, 'entry.js');
|
|
348
|
+
fs.writeFileSync(entryPath, entryCode);
|
|
349
|
+
|
|
350
|
+
// Bundle with esbuild
|
|
351
|
+
console.log('📦 Bundling with esbuild...');
|
|
352
|
+
await esbuild.build({
|
|
353
|
+
entryPoints: [entryPath],
|
|
354
|
+
bundle: true,
|
|
355
|
+
format: 'esm',
|
|
356
|
+
outfile: path.join(this.distDir, 'bundle.js'),
|
|
357
|
+
platform: 'browser',
|
|
358
|
+
target: 'es2020',
|
|
359
|
+
sourcemap: true,
|
|
360
|
+
external: []
|
|
361
|
+
});
|
|
647
362
|
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
363
|
+
// Generate index.html
|
|
364
|
+
console.log('📄 Generating index.html...');
|
|
365
|
+
const indexHtml = `<!DOCTYPE html>
|
|
366
|
+
<html lang="en">
|
|
367
|
+
<head>
|
|
368
|
+
<meta charset="UTF-8">
|
|
369
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
370
|
+
<title>JUX App</title>
|
|
371
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/juxscript@latest/lib/layouts/default.css">
|
|
372
|
+
</head>
|
|
373
|
+
<body>
|
|
374
|
+
<div id="app"></div>
|
|
375
|
+
<script type="module" src="/bundle.js"></script>
|
|
376
|
+
</body>
|
|
377
|
+
</html>`;
|
|
378
|
+
|
|
379
|
+
fs.writeFileSync(path.join(this.distDir, 'index.html'), indexHtml);
|
|
380
|
+
|
|
381
|
+
// Copy public folder
|
|
382
|
+
this.copyPublicFolder();
|
|
383
|
+
|
|
384
|
+
// Write source snapshot for error overlay
|
|
385
|
+
const snapshotPath = path.join(this.distDir, '__jux_sources.json');
|
|
386
|
+
fs.writeFileSync(snapshotPath, JSON.stringify(this._sourceSnapshot, null, 2));
|
|
387
|
+
|
|
388
|
+
const endTime = Date.now();
|
|
389
|
+
console.log(`\n✅ Build complete in ${endTime - startTime}ms`);
|
|
390
|
+
console.log(` Output: ${this.distDir}`);
|
|
391
|
+
|
|
392
|
+
this.reportValidationIssues();
|
|
393
|
+
|
|
394
|
+
return {
|
|
395
|
+
success: true,
|
|
396
|
+
errors: this._validationIssues || [],
|
|
397
|
+
distDir: this.distDir
|
|
398
|
+
};
|
|
659
399
|
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
window.addEventListener('popstate', () => navigate(location.pathname));
|
|
670
|
-
navigate(location.pathname);
|
|
671
|
-
`;
|
|
400
|
+
} catch (err) {
|
|
401
|
+
console.error('❌ Build failed:', err.message);
|
|
402
|
+
console.error(err.stack);
|
|
403
|
+
return {
|
|
404
|
+
success: false,
|
|
405
|
+
errors: [err.message]
|
|
406
|
+
};
|
|
407
|
+
}
|
|
672
408
|
}
|
|
673
409
|
|
|
674
410
|
/**
|