juxscript 1.1.137 → 1.1.139
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 +85 -71
- package/package.json +1 -1
package/dom-structure-map.json
CHANGED
package/machinery/compiler3.js
CHANGED
|
@@ -18,6 +18,7 @@ export class JuxCompiler {
|
|
|
18
18
|
this.paths = config.paths || {};
|
|
19
19
|
this._juxscriptExports = null;
|
|
20
20
|
this._juxscriptPath = null;
|
|
21
|
+
this._renderFunctionCounter = 0; // ✅ Add counter for unique IDs
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
/**
|
|
@@ -245,48 +246,46 @@ export class JuxCompiler {
|
|
|
245
246
|
|
|
246
247
|
entry += `\n// --- VIEW FUNCTIONS ---\n`;
|
|
247
248
|
|
|
249
|
+
// ✅ Map to store route → function name mappings
|
|
250
|
+
const routeToFunctionMap = new Map();
|
|
251
|
+
|
|
248
252
|
views.forEach(v => {
|
|
249
|
-
// ✅
|
|
250
|
-
|
|
251
|
-
const
|
|
252
|
-
.replace(/[\/\\.\\-\s]/g, '_') // Replace /, \, ., -, spaces with _
|
|
253
|
-
.replace(/[^a-zA-Z0-9_]/g, '_') // Replace any other invalid chars with _
|
|
254
|
-
.replace(/_+/g, '_') // Collapse multiple consecutive underscores
|
|
255
|
-
.replace(/^_|_$/g, ''); // Remove leading/trailing underscores
|
|
256
|
-
|
|
257
|
-
const capitalized = sanitizedName.charAt(0).toUpperCase() + sanitizedName.slice(1);
|
|
258
|
-
|
|
259
|
-
// ✅ Check for duplicate function names and warn
|
|
260
|
-
const functionName = `render${capitalized}`;
|
|
261
|
-
if (sourceSnapshot[functionName]) {
|
|
262
|
-
console.error(`❌ DUPLICATE FUNCTION NAME: ${functionName}`);
|
|
263
|
-
console.error(` Conflict between:`);
|
|
264
|
-
console.error(` 1. ${sourceSnapshot[functionName].file}`);
|
|
265
|
-
console.error(` 2. ${v.file}`);
|
|
266
|
-
console.error(` This will cause a build error. Rename one of these files.`);
|
|
267
|
-
throw new Error(`Duplicate function name: ${functionName}`);
|
|
268
|
-
}
|
|
253
|
+
// ✅ Generate TRULY UNIQUE serial ID
|
|
254
|
+
const serialId = this._renderFunctionCounter++;
|
|
255
|
+
const functionName = `renderJux${serialId}`;
|
|
269
256
|
|
|
270
257
|
sourceSnapshot[v.file] = {
|
|
271
258
|
name: v.name,
|
|
272
259
|
file: v.file,
|
|
273
260
|
content: v.content,
|
|
274
|
-
lines: v.content.split('\n')
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
// ✅ Also track by function name to catch duplicates
|
|
278
|
-
sourceSnapshot[functionName] = {
|
|
279
|
-
name: v.name,
|
|
280
|
-
file: v.file,
|
|
281
|
-
content: v.content,
|
|
282
|
-
lines: v.content.split('\n')
|
|
261
|
+
lines: v.content.split('\n'),
|
|
262
|
+
functionName // ✅ Store the unique function name
|
|
283
263
|
};
|
|
284
264
|
|
|
285
265
|
let viewCode = this.removeImports(v.content).replace(/^\s*export\s+default\s+.*$/gm, '');
|
|
286
266
|
const asyncPrefix = viewCode.includes('await ') ? 'async ' : '';
|
|
287
267
|
|
|
288
|
-
// Use
|
|
268
|
+
// ✅ Use truly unique serial function name
|
|
289
269
|
entry += `\n${asyncPrefix}function ${functionName}() {\n${viewCode}\n}\n`;
|
|
270
|
+
|
|
271
|
+
// ✅ Generate URL-safe route path from original name
|
|
272
|
+
const routePath = v.name
|
|
273
|
+
.toLowerCase()
|
|
274
|
+
.replace(/\\/g, '/')
|
|
275
|
+
.replace(/\.jux$/i, '')
|
|
276
|
+
.replace(/\./g, '-')
|
|
277
|
+
.replace(/\s+/g, '-')
|
|
278
|
+
.replace(/[^a-z0-9\/_-]/g, '')
|
|
279
|
+
.replace(/-+/g, '-')
|
|
280
|
+
.replace(/^-|-$/g, '');
|
|
281
|
+
|
|
282
|
+
// ✅ Handle index route
|
|
283
|
+
if (routePath === 'index' || routePath === '') {
|
|
284
|
+
routeToFunctionMap.set('/', functionName);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// ✅ Map route to function
|
|
288
|
+
routeToFunctionMap.set(`/${routePath}`, functionName);
|
|
290
289
|
});
|
|
291
290
|
|
|
292
291
|
dataModules.forEach(m => {
|
|
@@ -298,7 +297,9 @@ export class JuxCompiler {
|
|
|
298
297
|
|
|
299
298
|
this._sourceSnapshot = sourceSnapshot;
|
|
300
299
|
this._validationIssues = allIssues;
|
|
301
|
-
|
|
300
|
+
|
|
301
|
+
// ✅ Pass the route map to router generator
|
|
302
|
+
entry += this._generateRouter(routeToFunctionMap);
|
|
302
303
|
return entry;
|
|
303
304
|
}
|
|
304
305
|
|
|
@@ -319,39 +320,11 @@ export class JuxCompiler {
|
|
|
319
320
|
return { isValid: errors.length === 0, errors, warnings };
|
|
320
321
|
}
|
|
321
322
|
|
|
322
|
-
_generateRouter(
|
|
323
|
+
_generateRouter(routeToFunctionMap) {
|
|
324
|
+
// ✅ Build route map from Map object
|
|
323
325
|
let routeMap = '';
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
const sanitizedName = v.name
|
|
327
|
-
.replace(/[\/\\.\\-\s]/g, '_')
|
|
328
|
-
.replace(/[^a-zA-Z0-9_]/g, '_')
|
|
329
|
-
.replace(/_+/g, '_')
|
|
330
|
-
.replace(/^_|_$/g, '');
|
|
331
|
-
|
|
332
|
-
const cap = sanitizedName.charAt(0).toUpperCase() + sanitizedName.slice(1);
|
|
333
|
-
|
|
334
|
-
// ✅ Generate URL-safe route path from original name
|
|
335
|
-
// Convert: 'menus/main' → '/menus/main'
|
|
336
|
-
// Convert: 'about-us' → '/about-us'
|
|
337
|
-
// Convert: 'blog.post' → '/blog-post' (dots become dashes for URLs)
|
|
338
|
-
const routePath = v.name
|
|
339
|
-
.toLowerCase()
|
|
340
|
-
.replace(/\\/g, '/') // Normalize backslashes to forward slashes
|
|
341
|
-
.replace(/\.jux$/i, '') // Remove .jux extension if present
|
|
342
|
-
.replace(/\./g, '-') // Convert dots to dashes (blog.post → blog-post)
|
|
343
|
-
.replace(/\s+/g, '-') // Convert spaces to dashes
|
|
344
|
-
.replace(/[^a-z0-9\/_-]/g, '') // Remove any other unsafe URL chars
|
|
345
|
-
.replace(/-+/g, '-') // Collapse multiple dashes
|
|
346
|
-
.replace(/^-|-$/g, ''); // Remove leading/trailing dashes
|
|
347
|
-
|
|
348
|
-
// ✅ Handle index route
|
|
349
|
-
if (routePath === 'index' || routePath === '') {
|
|
350
|
-
routeMap += ` '/': render${cap},\n`;
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
// ✅ Add regular route
|
|
354
|
-
routeMap += ` '/${routePath}': render${cap},\n`;
|
|
326
|
+
routeToFunctionMap.forEach((functionName, route) => {
|
|
327
|
+
routeMap += ` '${route}': ${functionName},\n`;
|
|
355
328
|
});
|
|
356
329
|
|
|
357
330
|
return `
|
|
@@ -369,12 +342,12 @@ async function __juxLoadSources() {
|
|
|
369
342
|
}
|
|
370
343
|
|
|
371
344
|
function __juxFindSource(stack) {
|
|
372
|
-
var match = stack.match(/
|
|
345
|
+
var match = stack.match(/renderJux(\\d+)/);
|
|
373
346
|
if (match) {
|
|
374
|
-
var
|
|
347
|
+
var functionName = 'renderJux' + match[1];
|
|
375
348
|
for (var file in __juxSources || {}) {
|
|
376
|
-
if (__juxSources[file].
|
|
377
|
-
return { file: file, source: __juxSources[file],
|
|
349
|
+
if (__juxSources[file].functionName === functionName) {
|
|
350
|
+
return { file: file, source: __juxSources[file], functionName: functionName };
|
|
378
351
|
}
|
|
379
352
|
}
|
|
380
353
|
}
|
|
@@ -537,12 +510,11 @@ document.addEventListener('click', (e) => {
|
|
|
537
510
|
const juxDistDir = path.join(this.distDir, 'jux');
|
|
538
511
|
fs.mkdirSync(juxDistDir, { recursive: true });
|
|
539
512
|
|
|
540
|
-
// ✅
|
|
513
|
+
// ✅ Create subdirectories and copy files
|
|
541
514
|
[...dataModules, ...sharedModules].forEach(m => {
|
|
542
515
|
const destPath = path.join(juxDistDir, m.file);
|
|
543
516
|
const destDir = path.dirname(destPath);
|
|
544
517
|
|
|
545
|
-
// Create subdirectory if it doesn't exist
|
|
546
518
|
if (!fs.existsSync(destDir)) {
|
|
547
519
|
fs.mkdirSync(destDir, { recursive: true });
|
|
548
520
|
}
|
|
@@ -574,15 +546,57 @@ document.addEventListener('click', (e) => {
|
|
|
574
546
|
platform: 'browser',
|
|
575
547
|
target: 'esnext',
|
|
576
548
|
sourcemap: true,
|
|
577
|
-
|
|
549
|
+
|
|
550
|
+
// ✅ FIX: Remove external packages restriction - bundle EVERYTHING
|
|
551
|
+
// This allows axios, lodash, date-fns, etc. to be bundled
|
|
552
|
+
// Remove the packages: 'external' or external: [...] config
|
|
553
|
+
|
|
554
|
+
loader: {
|
|
555
|
+
'.jux': 'js',
|
|
556
|
+
'.css': 'empty'
|
|
557
|
+
},
|
|
558
|
+
|
|
578
559
|
plugins: [{
|
|
579
560
|
name: 'juxscript-resolver',
|
|
580
561
|
setup: (build) => {
|
|
581
|
-
|
|
562
|
+
// Only resolve juxscript - everything else gets bundled normally
|
|
563
|
+
build.onResolve({ filter: /^juxscript$/ }, () => ({
|
|
564
|
+
path: juxscriptPath
|
|
565
|
+
}));
|
|
582
566
|
}
|
|
583
567
|
}],
|
|
568
|
+
|
|
569
|
+
// ✅ NEW: Minify and tree-shake in production
|
|
570
|
+
minify: process.env.NODE_ENV === 'production',
|
|
571
|
+
treeShaking: true,
|
|
572
|
+
|
|
573
|
+
// ✅ NEW: Handle node built-ins (like 'http', 'fs') that axios might use
|
|
574
|
+
// These should NOT be bundled (they don't work in browser)
|
|
575
|
+
external: [
|
|
576
|
+
'fs',
|
|
577
|
+
'path',
|
|
578
|
+
'http',
|
|
579
|
+
'https',
|
|
580
|
+
'stream',
|
|
581
|
+
'zlib',
|
|
582
|
+
'crypto'
|
|
583
|
+
],
|
|
584
|
+
|
|
585
|
+
// ✅ NEW: Define globals for node built-ins
|
|
586
|
+
define: {
|
|
587
|
+
'process.env.NODE_ENV': '"production"',
|
|
588
|
+
'global': 'window'
|
|
589
|
+
}
|
|
584
590
|
});
|
|
591
|
+
|
|
585
592
|
console.log('✅ esbuild complete');
|
|
593
|
+
|
|
594
|
+
// ✅ Show bundle size
|
|
595
|
+
const bundlePath = path.join(this.distDir, 'bundle.js');
|
|
596
|
+
const bundleStats = fs.statSync(bundlePath);
|
|
597
|
+
const bundleSizeKB = (bundleStats.size / 1024).toFixed(2);
|
|
598
|
+
console.log(`📦 Bundle size: ${bundleSizeKB} KB`);
|
|
599
|
+
|
|
586
600
|
} catch (err) {
|
|
587
601
|
console.error('❌ esbuild failed:', err);
|
|
588
602
|
return { success: false, errors: [{ message: err.message }], warnings: [] };
|