slicejs-cli 2.9.0 → 2.9.2
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.
|
@@ -467,7 +467,7 @@ export default class BundleGenerator {
|
|
|
467
467
|
'critical',
|
|
468
468
|
criticalFile.file
|
|
469
469
|
);
|
|
470
|
-
this.bundles.critical.integrity =
|
|
470
|
+
this.bundles.critical.integrity = `sha256:${criticalFile.hash}`;
|
|
471
471
|
this.bundles.critical.hash = criticalFile.hash;
|
|
472
472
|
files.push(criticalFile);
|
|
473
473
|
}
|
|
@@ -483,13 +483,7 @@ export default class BundleGenerator {
|
|
|
483
483
|
'route',
|
|
484
484
|
routeIdentifier
|
|
485
485
|
);
|
|
486
|
-
const routeIntegrity =
|
|
487
|
-
bundle.components,
|
|
488
|
-
'route',
|
|
489
|
-
routeIdentifier,
|
|
490
|
-
this.routeToFileName(routeIdentifier),
|
|
491
|
-
routeFile.file
|
|
492
|
-
);
|
|
486
|
+
const routeIntegrity = `sha256:${routeFile.hash}`;
|
|
493
487
|
const matchingBundle = Object.values(this.bundles.routes)
|
|
494
488
|
.find((entry) => entry.file === routeFile.file);
|
|
495
489
|
if (matchingBundle) {
|
|
@@ -540,7 +534,11 @@ export default class BundleGenerator {
|
|
|
540
534
|
return bundleContent;
|
|
541
535
|
}
|
|
542
536
|
|
|
543
|
-
const
|
|
537
|
+
const options = {
|
|
538
|
+
parse: {
|
|
539
|
+
ecma: 2022
|
|
540
|
+
},
|
|
541
|
+
ecma: 2022,
|
|
544
542
|
compress: this.options.minify ? {
|
|
545
543
|
drop_console: false,
|
|
546
544
|
drop_debugger: true,
|
|
@@ -552,12 +550,39 @@ export default class BundleGenerator {
|
|
|
552
550
|
keep_fnames: true,
|
|
553
551
|
keep_classnames: true,
|
|
554
552
|
format: {
|
|
555
|
-
comments: false
|
|
553
|
+
comments: false,
|
|
554
|
+
ecma: 2022
|
|
556
555
|
}
|
|
557
|
-
}
|
|
556
|
+
};
|
|
557
|
+
|
|
558
|
+
let result;
|
|
559
|
+
try {
|
|
560
|
+
result = await terserMinify(bundleContent, options);
|
|
561
|
+
} catch (error) {
|
|
562
|
+
const tmpDir = path.resolve(process.cwd(), '.tmp');
|
|
563
|
+
const safeName = fileName.replace(/[^a-zA-Z0-9_.-]/g, '_');
|
|
564
|
+
const tmpPath = path.join(tmpDir, `terser-fail-${safeName}`);
|
|
565
|
+
try {
|
|
566
|
+
await fs.ensureDir(tmpDir);
|
|
567
|
+
await fs.writeFile(tmpPath, bundleContent, 'utf-8');
|
|
568
|
+
} catch (writeError) {
|
|
569
|
+
console.warn(`Warning: Failed to write ${tmpPath}:`, writeError.message);
|
|
570
|
+
}
|
|
571
|
+
const message = error?.message ? `${error.message}.` : 'Unknown Terser error.';
|
|
572
|
+
throw new Error(`Terser failed for ${fileName}: ${message} Saved bundle to ${tmpPath}`);
|
|
573
|
+
}
|
|
558
574
|
|
|
559
575
|
if (result.error) {
|
|
560
|
-
|
|
576
|
+
const tmpDir = path.resolve(process.cwd(), '.tmp');
|
|
577
|
+
const safeName = fileName.replace(/[^a-zA-Z0-9_.-]/g, '_');
|
|
578
|
+
const tmpPath = path.join(tmpDir, `terser-fail-${safeName}`);
|
|
579
|
+
try {
|
|
580
|
+
await fs.ensureDir(tmpDir);
|
|
581
|
+
await fs.writeFile(tmpPath, bundleContent, 'utf-8');
|
|
582
|
+
} catch (writeError) {
|
|
583
|
+
console.warn(`Warning: Failed to write ${tmpPath}:`, writeError.message);
|
|
584
|
+
}
|
|
585
|
+
throw new Error(`Terser failed for ${fileName}: ${result.error.message}. Saved bundle to ${tmpPath}`);
|
|
561
586
|
}
|
|
562
587
|
|
|
563
588
|
return result.code || bundleContent;
|
|
@@ -737,11 +762,30 @@ export default class BundleGenerator {
|
|
|
737
762
|
// Remove imports (components will already be available)
|
|
738
763
|
code = code.replace(/import\s+.*?from\s+['"].*?['"];?\s*/g, '');
|
|
739
764
|
|
|
765
|
+
// Guard customElements.define to avoid duplicate registrations
|
|
766
|
+
code = code.replace(
|
|
767
|
+
/customElements\.define\(([^)]+)\);?/g,
|
|
768
|
+
(match, args) => {
|
|
769
|
+
const firstArg = args.split(',')[0]?.trim() || '';
|
|
770
|
+
if (!/^['"][^'"]+['"]$/.test(firstArg)) {
|
|
771
|
+
return match;
|
|
772
|
+
}
|
|
773
|
+
return `if (!customElements.get(${firstArg})) { customElements.define(${args}); }`;
|
|
774
|
+
}
|
|
775
|
+
);
|
|
776
|
+
|
|
740
777
|
// Make sure the class is available globally for bundle evaluation
|
|
741
778
|
// Preserve original customElements.define if it exists
|
|
742
779
|
if (code.includes('customElements.define')) {
|
|
743
|
-
// Add global assignment before customElements.define
|
|
744
|
-
|
|
780
|
+
// Add global assignment before guarded or direct customElements.define
|
|
781
|
+
const globalAssignment = `window.${componentName} = ${componentName};\n`;
|
|
782
|
+
const guardedDefineRegex = /if\s*\(\s*!\s*customElements\.get\([^)]*\)\s*\)\s*\{\s*customElements\.define\([^;]+\);?\s*\}\s*$/;
|
|
783
|
+
const directDefineRegex = /customElements\.define\([^;]+\);?\s*$/;
|
|
784
|
+
if (guardedDefineRegex.test(code)) {
|
|
785
|
+
code = code.replace(guardedDefineRegex, `${globalAssignment}$&`);
|
|
786
|
+
} else {
|
|
787
|
+
code = code.replace(directDefineRegex, `${globalAssignment}$&`);
|
|
788
|
+
}
|
|
745
789
|
} else {
|
|
746
790
|
// If no customElements.define found, just assign to global
|
|
747
791
|
code += `\nwindow.${componentName} = ${componentName};`;
|
|
@@ -1072,7 +1116,7 @@ if (window.slice && window.slice.controller) {
|
|
|
1072
1116
|
await fs.writeFile(filePath, finalContent, 'utf-8');
|
|
1073
1117
|
|
|
1074
1118
|
const hash = crypto.createHash('sha256').update(finalContent).digest('hex');
|
|
1075
|
-
const integrity =
|
|
1119
|
+
const integrity = `sha256:${hash}`;
|
|
1076
1120
|
|
|
1077
1121
|
return {
|
|
1078
1122
|
name: 'framework',
|
|
@@ -3,7 +3,7 @@ import fs from 'fs-extra';
|
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import { parse } from '@babel/parser';
|
|
5
5
|
import traverse from '@babel/traverse';
|
|
6
|
-
import { getSrcPath, getComponentsJsPath, getProjectRoot } from '../PathHelper.js';
|
|
6
|
+
import { getSrcPath, getComponentsJsPath, getProjectRoot, getConfigPath } from '../PathHelper.js';
|
|
7
7
|
|
|
8
8
|
export default class DependencyAnalyzer {
|
|
9
9
|
constructor(moduleUrl) {
|
|
@@ -64,11 +64,21 @@ export default class DependencyAnalyzer {
|
|
|
64
64
|
*/
|
|
65
65
|
async loadComponentsConfig() {
|
|
66
66
|
const componentsConfigPath = path.join(this.componentsPath, 'components.js');
|
|
67
|
+
const configPath = getConfigPath(this.moduleUrl);
|
|
68
|
+
let sliceConfig = {};
|
|
67
69
|
|
|
68
70
|
if (!await fs.pathExists(componentsConfigPath)) {
|
|
69
71
|
throw new Error('components.js not found');
|
|
70
72
|
}
|
|
71
73
|
|
|
74
|
+
if (await fs.pathExists(configPath)) {
|
|
75
|
+
try {
|
|
76
|
+
sliceConfig = await fs.readJson(configPath);
|
|
77
|
+
} catch (error) {
|
|
78
|
+
console.warn('Warning: Could not read sliceConfig.json for component paths:', error.message);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
72
82
|
// Read and parse components.js
|
|
73
83
|
const content = await fs.readFile(componentsConfigPath, 'utf-8');
|
|
74
84
|
|
|
@@ -87,13 +97,18 @@ export default class DependencyAnalyzer {
|
|
|
87
97
|
|
|
88
98
|
// Process each category
|
|
89
99
|
for (const [categoryName, componentList] of categoryMap) {
|
|
90
|
-
|
|
91
|
-
|
|
100
|
+
const configCategory = sliceConfig?.paths?.components?.[categoryName];
|
|
101
|
+
|
|
102
|
+
// Determine category type based on config or category name
|
|
103
|
+
let categoryType = configCategory?.type || 'Visual';
|
|
92
104
|
if (categoryName === 'Service') categoryType = 'Service';
|
|
93
105
|
if (categoryName === 'AppComponents') categoryType = 'Visual'; // AppComponents are visual
|
|
94
106
|
|
|
95
|
-
//
|
|
96
|
-
|
|
107
|
+
// Resolve category path from config if available
|
|
108
|
+
let categoryPath = path.join(this.componentsPath, categoryName);
|
|
109
|
+
if (configCategory?.path) {
|
|
110
|
+
categoryPath = getSrcPath(this.moduleUrl, configCategory.path);
|
|
111
|
+
}
|
|
97
112
|
|
|
98
113
|
if (await fs.pathExists(categoryPath)) {
|
|
99
114
|
const files = await fs.readdir(categoryPath);
|
|
@@ -330,6 +345,17 @@ export default class DependencyAnalyzer {
|
|
|
330
345
|
return node;
|
|
331
346
|
}
|
|
332
347
|
|
|
348
|
+
if (node.type === 'CallExpression') {
|
|
349
|
+
const calleeName = node.callee?.name || null;
|
|
350
|
+
if (calleeName && node.arguments?.length) {
|
|
351
|
+
const firstArg = node.arguments[0];
|
|
352
|
+
const resolvedObject = resolveObjectExpression(firstArg, scope);
|
|
353
|
+
if (resolvedObject) {
|
|
354
|
+
return resolvedObject;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
333
359
|
if (node.type === 'ObjectExpression') {
|
|
334
360
|
const routesProp = node.properties.find(p => p.key?.name === 'routes');
|
|
335
361
|
if (routesProp?.value) {
|
|
@@ -348,6 +374,10 @@ export default class DependencyAnalyzer {
|
|
|
348
374
|
return init;
|
|
349
375
|
}
|
|
350
376
|
|
|
377
|
+
if (init?.type === 'CallExpression') {
|
|
378
|
+
return resolveRoutesArray(init, binding.path.scope);
|
|
379
|
+
}
|
|
380
|
+
|
|
351
381
|
if (init?.type === 'Identifier') {
|
|
352
382
|
return resolveRoutesArray(init, binding.path.scope);
|
|
353
383
|
}
|
|
@@ -562,8 +592,46 @@ export default class DependencyAnalyzer {
|
|
|
562
592
|
return null;
|
|
563
593
|
};
|
|
564
594
|
|
|
595
|
+
const addRouteConfigDependencies = (routesConfigNode, scope) => {
|
|
596
|
+
if (!routesConfigNode || routesConfigNode.type !== 'ObjectExpression') return;
|
|
597
|
+
|
|
598
|
+
const processObject = (node) => {
|
|
599
|
+
if (!node || node.type !== 'ObjectExpression') return;
|
|
600
|
+
|
|
601
|
+
const componentProp = node.properties.find(p => p.key?.name === 'component');
|
|
602
|
+
if (componentProp?.value) {
|
|
603
|
+
const componentName = resolveStringValue(componentProp.value, scope);
|
|
604
|
+
if (componentName) {
|
|
605
|
+
dependencies.add(componentName);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
const itemsProp = node.properties.find(p => p.key?.name === 'items');
|
|
610
|
+
if (itemsProp?.value) {
|
|
611
|
+
const itemsNode = resolveRoutesArray(itemsProp.value, scope);
|
|
612
|
+
addMultiRouteDependencies(itemsNode, scope);
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
node.properties.forEach((prop) => {
|
|
616
|
+
const valueNode = prop.value;
|
|
617
|
+
if (valueNode?.type === 'ObjectExpression') {
|
|
618
|
+
processObject(valueNode);
|
|
619
|
+
}
|
|
620
|
+
});
|
|
621
|
+
};
|
|
622
|
+
|
|
623
|
+
processObject(routesConfigNode);
|
|
624
|
+
};
|
|
625
|
+
|
|
565
626
|
const addMultiRouteDependencies = (routesArrayNode, scope) => {
|
|
566
|
-
if (!routesArrayNode
|
|
627
|
+
if (!routesArrayNode) return;
|
|
628
|
+
|
|
629
|
+
if (routesArrayNode.type === 'ObjectExpression') {
|
|
630
|
+
addRouteConfigDependencies(routesArrayNode, scope);
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
if (routesArrayNode.type !== 'ArrayExpression') return;
|
|
567
635
|
|
|
568
636
|
routesArrayNode.elements.forEach(routeElement => {
|
|
569
637
|
if (!routeElement) return;
|
|
@@ -583,6 +651,12 @@ export default class DependencyAnalyzer {
|
|
|
583
651
|
dependencies.add(componentName);
|
|
584
652
|
}
|
|
585
653
|
}
|
|
654
|
+
|
|
655
|
+
const itemsProp = routeObject.properties.find(p => p.key?.name === 'items');
|
|
656
|
+
if (itemsProp?.value) {
|
|
657
|
+
const itemsNode = resolveRoutesArray(itemsProp.value, scope);
|
|
658
|
+
addMultiRouteDependencies(itemsNode, scope);
|
|
659
|
+
}
|
|
586
660
|
}
|
|
587
661
|
});
|
|
588
662
|
};
|