slicejs-web-framework 3.4.4 → 3.5.1

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.
Files changed (110) hide show
  1. package/Slice/Components/Structural/Controller/Controller.js +135 -0
  2. package/Slice/Components/Structural/EventManager/EventManager.js +289 -4
  3. package/Slice/Components/Structural/EventManager/EventManagerDebugger.js +368 -30
  4. package/Slice/Components/Structural/LeakInspector/LeakInspector.js +296 -0
  5. package/Slice/Components/Structural/StylesManager/ThemeManager/ThemeManager.js +56 -0
  6. package/Slice/Slice.js +14 -1
  7. package/Slice/tests/event-emitters.test.js +79 -0
  8. package/Slice/tests/event-registry.test.js +141 -0
  9. package/Slice/tests/leak-orphans.test.js +131 -0
  10. package/api/{middleware → framework}/securityMiddleware.js +18 -74
  11. package/api/framework/server.js +333 -0
  12. package/api/index.js +5 -279
  13. package/api/tests/public-env-resolver.test.js +1 -1
  14. package/package.json +4 -2
  15. package/sliceConfig.schema.json +10 -1
  16. package/src/App/index.html +31 -1
  17. package/src/manifest.json +15 -0
  18. package/src/robots.txt +4 -0
  19. package/src/sitemap.xml +8 -0
  20. package/src/sliceConfig.json +5 -1
  21. package/types/index.d.ts +12 -0
  22. package/slicejs-cli/.github/workflows/ci.yml +0 -43
  23. package/slicejs-cli/LICENSE +0 -21
  24. package/slicejs-cli/assets/Slice.js-logo.png +0 -0
  25. package/slicejs-cli/client.js +0 -740
  26. package/slicejs-cli/commands/Print.js +0 -164
  27. package/slicejs-cli/commands/Validations.js +0 -92
  28. package/slicejs-cli/commands/build/build.js +0 -40
  29. package/slicejs-cli/commands/buildProduction/buildProduction.js +0 -577
  30. package/slicejs-cli/commands/bundle/bundle.js +0 -236
  31. package/slicejs-cli/commands/createComponent/VisualComponentTemplate.js +0 -55
  32. package/slicejs-cli/commands/createComponent/createComponent.js +0 -128
  33. package/slicejs-cli/commands/deleteComponent/deleteComponent.js +0 -81
  34. package/slicejs-cli/commands/doctor/doctor.js +0 -516
  35. package/slicejs-cli/commands/getComponent/getComponent.js +0 -695
  36. package/slicejs-cli/commands/init/init.js +0 -473
  37. package/slicejs-cli/commands/listComponents/listComponents.js +0 -172
  38. package/slicejs-cli/commands/startServer/startServer.js +0 -240
  39. package/slicejs-cli/commands/startServer/watchServer.js +0 -66
  40. package/slicejs-cli/commands/types/types.js +0 -583
  41. package/slicejs-cli/commands/utils/LocalCliDelegation.js +0 -53
  42. package/slicejs-cli/commands/utils/PackageManager.js +0 -148
  43. package/slicejs-cli/commands/utils/PathHelper.js +0 -75
  44. package/slicejs-cli/commands/utils/VersionChecker.js +0 -169
  45. package/slicejs-cli/commands/utils/bundling/BundleGenerator.js +0 -2525
  46. package/slicejs-cli/commands/utils/bundling/DependencyAnalyzer.js +0 -933
  47. package/slicejs-cli/commands/utils/loadConfig.js +0 -31
  48. package/slicejs-cli/commands/utils/sliceScripts.js +0 -48
  49. package/slicejs-cli/commands/utils/updateManager.js +0 -471
  50. package/slicejs-cli/package.json +0 -71
  51. package/slicejs-cli/playwright.config.js +0 -51
  52. package/slicejs-cli/pnpm-lock.yaml +0 -1629
  53. package/slicejs-cli/tests/build-command-integration.test.js +0 -87
  54. package/slicejs-cli/tests/build-mangling-e2e.test.js +0 -290
  55. package/slicejs-cli/tests/build-production-e2e.test.js +0 -140
  56. package/slicejs-cli/tests/builder-edge-cases.test.js +0 -322
  57. package/slicejs-cli/tests/bundle-generate-e2e.test.js +0 -115
  58. package/slicejs-cli/tests/bundle-generator.test.js +0 -691
  59. package/slicejs-cli/tests/bundle-v2-register-output.test.js +0 -470
  60. package/slicejs-cli/tests/bundling-dependency-edges.test.js +0 -127
  61. package/slicejs-cli/tests/bundling-imports-unit.test.js +0 -267
  62. package/slicejs-cli/tests/client-launcher-contract.test.js +0 -211
  63. package/slicejs-cli/tests/commands-component-crud.test.js +0 -128
  64. package/slicejs-cli/tests/commands-doctor.test.js +0 -152
  65. package/slicejs-cli/tests/commands-version-checker.test.js +0 -37
  66. package/slicejs-cli/tests/component-registry-parse.test.js +0 -34
  67. package/slicejs-cli/tests/dependency-analyzer.test.js +0 -24
  68. package/slicejs-cli/tests/e2e/bundles.spec.js +0 -91
  69. package/slicejs-cli/tests/e2e/dependency-scenarios.spec.js +0 -56
  70. package/slicejs-cli/tests/e2e/fixtures/components/Service/FetchManager/FetchManager.js +0 -136
  71. package/slicejs-cli/tests/e2e/fixtures/components/Service/IndexedDbManager/IndexedDbManager.js +0 -149
  72. package/slicejs-cli/tests/e2e/fixtures/components/Service/LocalStorageManager/LocalStorageManager.js +0 -45
  73. package/slicejs-cli/tests/e2e/fixtures/components/Visual/Button/Button.css +0 -106
  74. package/slicejs-cli/tests/e2e/fixtures/components/Visual/Button/Button.html +0 -5
  75. package/slicejs-cli/tests/e2e/fixtures/components/Visual/Button/Button.js +0 -158
  76. package/slicejs-cli/tests/e2e/fixtures/components/Visual/Link/Link.js +0 -33
  77. package/slicejs-cli/tests/e2e/fixtures/components/Visual/Loading/Loading.css +0 -56
  78. package/slicejs-cli/tests/e2e/fixtures/components/Visual/Loading/Loading.html +0 -83
  79. package/slicejs-cli/tests/e2e/fixtures/components/Visual/Loading/Loading.js +0 -164
  80. package/slicejs-cli/tests/e2e/fixtures/components/Visual/MultiRoute/MultiRoute.js +0 -167
  81. package/slicejs-cli/tests/e2e/fixtures/components/Visual/Navbar/Navbar.css +0 -116
  82. package/slicejs-cli/tests/e2e/fixtures/components/Visual/Navbar/Navbar.html +0 -44
  83. package/slicejs-cli/tests/e2e/fixtures/components/Visual/Navbar/Navbar.js +0 -180
  84. package/slicejs-cli/tests/e2e/fixtures/components/Visual/NotFound/NotFound.js +0 -20
  85. package/slicejs-cli/tests/e2e/fixtures/components/Visual/Route/Route.js +0 -181
  86. package/slicejs-cli/tests/e2e/fixtures/components/registry.json +0 -12
  87. package/slicejs-cli/tests/e2e/fixtures/vendor-components.mjs +0 -65
  88. package/slicejs-cli/tests/e2e/navigation.spec.js +0 -44
  89. package/slicejs-cli/tests/e2e/render.spec.js +0 -34
  90. package/slicejs-cli/tests/e2e/serve.mjs +0 -264
  91. package/slicejs-cli/tests/e2e/shared-deps.spec.js +0 -61
  92. package/slicejs-cli/tests/e2e/unminified.spec.js +0 -33
  93. package/slicejs-cli/tests/e2e-serve.test.js +0 -148
  94. package/slicejs-cli/tests/fixtures/components.js +0 -8
  95. package/slicejs-cli/tests/fixtures/sliceConfig.json +0 -74
  96. package/slicejs-cli/tests/getcomponent.test.js +0 -435
  97. package/slicejs-cli/tests/helpers/setup.js +0 -102
  98. package/slicejs-cli/tests/init-command-contract.test.js +0 -101
  99. package/slicejs-cli/tests/init-e2e.test.js +0 -82
  100. package/slicejs-cli/tests/init-project-isolation.test.js +0 -98
  101. package/slicejs-cli/tests/local-cli-delegation.test.js +0 -81
  102. package/slicejs-cli/tests/package-manager.test.js +0 -127
  103. package/slicejs-cli/tests/path-helper.test.js +0 -206
  104. package/slicejs-cli/tests/perf-budget.test.js +0 -84
  105. package/slicejs-cli/tests/postinstall-command.test.js +0 -103
  106. package/slicejs-cli/tests/property-mangling-regression.test.js +0 -182
  107. package/slicejs-cli/tests/types-breakage.test.js +0 -491
  108. package/slicejs-cli/tests/types-generator-errors.test.js +0 -361
  109. package/slicejs-cli/tests/types-generator.test.js +0 -348
  110. /package/api/{utils → framework}/publicEnvResolver.js +0 -0
@@ -1,577 +0,0 @@
1
- // commands/buildProduction/buildProduction.js - CLEAN VERSION
2
-
3
- import fs from 'fs-extra';
4
- import path from 'path';
5
- import { minify as terserMinify } from 'terser';
6
- import { minify } from 'html-minifier-terser';
7
- import CleanCSS from 'clean-css';
8
- import Print from '../Print.js';
9
- import { getSrcPath, getDistPath, getConfigPath, getProjectRoot } from '../utils/PathHelper.js';
10
- import { resolvePackageManager, runScriptCommand } from '../utils/PackageManager.js';
11
-
12
- /**
13
- * Loads configuration from sliceConfig.json
14
- */
15
- const loadConfig = () => {
16
- try {
17
- const configPath = getConfigPath(import.meta.url);
18
- const rawData = fs.readFileSync(configPath, 'utf-8');
19
- return JSON.parse(rawData);
20
- } catch (error) {
21
- Print.error(`Loading configuration: ${error.message}`);
22
- return null;
23
- }
24
- };
25
-
26
- /**
27
- * Checks necessary build dependencies
28
- */
29
- async function checkBuildDependencies() {
30
- const srcDir = getSrcPath(import.meta.url);
31
-
32
- if (!await fs.pathExists(srcDir)) {
33
- Print.error('Source directory (/src) not found');
34
- Print.info('Run "slice init" to initialize your project');
35
- return false;
36
- }
37
-
38
- try {
39
- await import('terser');
40
- await import('clean-css');
41
- await import('html-minifier-terser');
42
- Print.success('Build dependencies available');
43
- return true;
44
- } catch (error) {
45
- Print.warning('Some build dependencies missing - using fallback copy mode');
46
- return true;
47
- }
48
- }
49
-
50
- /**
51
- * Verifies that critical Slice.js files exist
52
- */
53
- async function verifySliceFiles(srcDir) {
54
- Print.info('Verifying Slice.js critical files...');
55
-
56
- const criticalFiles = [
57
- 'sliceConfig.json',
58
- 'Components/components.js',
59
- 'App/index.js'
60
- ];
61
-
62
- for (const file of criticalFiles) {
63
- const filePath = path.join(srcDir, file);
64
- if (!await fs.pathExists(filePath)) {
65
- throw new Error(`Critical Slice.js file missing: ${file}`);
66
- }
67
- }
68
-
69
- Print.success('All critical Slice.js files verified');
70
- }
71
-
72
- /**
73
- * Verifies build integrity for Slice.js
74
- */
75
- async function verifyBuildIntegrity(distDir) {
76
- Print.info('Verifying build integrity for Slice.js...');
77
-
78
- const criticalBuiltFiles = [
79
- 'sliceConfig.json',
80
- 'Components/components.js',
81
- 'App/index.js'
82
- ];
83
-
84
- for (const file of criticalBuiltFiles) {
85
- const filePath = path.join(distDir, file);
86
- if (!await fs.pathExists(filePath)) {
87
- throw new Error(`Critical built file missing: ${file}`);
88
- }
89
-
90
- if (file === 'Components/components.js') {
91
- const content = await fs.readFile(filePath, 'utf8');
92
- if (!content.includes('const components') || !content.includes('export default')) {
93
- throw new Error('components.js structure corrupted during build');
94
- }
95
- }
96
- }
97
-
98
- Print.success('Build integrity verified - all Slice.js components preserved');
99
- }
100
-
101
- /**
102
- * Copies sliceConfig.json to the dist directory
103
- */
104
- async function copySliceConfig() {
105
- const srcConfig = getConfigPath(import.meta.url);
106
- const distConfig = getDistPath(import.meta.url, 'sliceConfig.json');
107
-
108
- if (await fs.pathExists(srcConfig)) {
109
- await fs.copy(srcConfig, distConfig);
110
- Print.info('sliceConfig.json copied to dist');
111
- }
112
- }
113
-
114
- /**
115
- * Processes a complete directory
116
- */
117
- async function processDirectory(srcPath, distPath, baseSrcPath, options) {
118
- const items = await fs.readdir(srcPath);
119
-
120
- for (const item of items) {
121
- const srcItemPath = path.join(srcPath, item);
122
- const distItemPath = path.join(distPath, item);
123
- const stat = await fs.stat(srcItemPath);
124
-
125
- if (stat.isDirectory()) {
126
- await fs.ensureDir(distItemPath);
127
- await processDirectory(srcItemPath, distItemPath, baseSrcPath, options);
128
- } else {
129
- await processFile(srcItemPath, distItemPath, options);
130
- }
131
- }
132
- }
133
-
134
- /**
135
- * Processes an individual file
136
- */
137
- async function processFile(srcFilePath, distFilePath, options) {
138
- const ext = path.extname(srcFilePath).toLowerCase();
139
- const fileName = path.basename(srcFilePath);
140
- const isBundleConfig = fileName === 'bundle.config.json' || fileName === 'bundle.config.js';
141
- const isBundleFolder = srcFilePath.includes(`${path.sep}bundles${path.sep}`);
142
-
143
- if (isBundleConfig && isBundleFolder) {
144
- const renamed = fileName.replace('bundle.config', 'bundle.build.config');
145
- distFilePath = path.join(path.dirname(distFilePath), renamed);
146
- }
147
-
148
- try {
149
- if (fileName === 'components.js') {
150
- if (options?.minify === false) {
151
- await fs.copy(srcFilePath, distFilePath);
152
- const stat = await fs.stat(srcFilePath);
153
- const sizeKB = (stat.size / 1024).toFixed(1);
154
- Print.info(`📄 Copied: ${fileName} (${sizeKB} KB)`);
155
- } else {
156
- await processComponentsFile(srcFilePath, distFilePath);
157
- }
158
- } else if (ext === '.js') {
159
- if (options?.minify === false) {
160
- await fs.copy(srcFilePath, distFilePath);
161
- const stat = await fs.stat(srcFilePath);
162
- const sizeKB = (stat.size / 1024).toFixed(1);
163
- Print.info(`📄 Copied: ${fileName} (${sizeKB} KB)`);
164
- } else {
165
- await minifyJavaScript(srcFilePath, distFilePath);
166
- }
167
- } else if (ext === '.css') {
168
- if (options?.minify === false) {
169
- await fs.copy(srcFilePath, distFilePath);
170
- const stat = await fs.stat(srcFilePath);
171
- const sizeKB = (stat.size / 1024).toFixed(1);
172
- Print.info(`📄 Copied: ${fileName} (${sizeKB} KB)`);
173
- } else {
174
- await minifyCSS(srcFilePath, distFilePath);
175
- }
176
- } else if (ext === '.html') {
177
- if (options?.minify === false) {
178
- await fs.copy(srcFilePath, distFilePath);
179
- const stat = await fs.stat(srcFilePath);
180
- const sizeKB = (stat.size / 1024).toFixed(1);
181
- Print.info(`📄 Copied: ${fileName} (${sizeKB} KB)`);
182
- } else {
183
- await minifyHTML(srcFilePath, distFilePath);
184
- }
185
- } else if (fileName === 'sliceConfig.json') {
186
- await fs.copy(srcFilePath, distFilePath);
187
- Print.info(`📄 Preserved: ${fileName} (configuration file)`);
188
- } else {
189
- await fs.copy(srcFilePath, distFilePath);
190
- const stat = await fs.stat(srcFilePath);
191
- const sizeKB = (stat.size / 1024).toFixed(1);
192
- Print.info(`📄 Copied: ${fileName} (${sizeKB} KB)`);
193
- }
194
- } catch (error) {
195
- Print.error(`Processing ${fileName}: ${error.message}`);
196
- await fs.copy(srcFilePath, distFilePath);
197
- }
198
- }
199
-
200
- /**
201
- * Processes the components.js file in a special way
202
- */
203
- async function processComponentsFile(srcPath, distPath) {
204
- const content = await fs.readFile(srcPath, 'utf8');
205
- const originalSize = Buffer.byteLength(content, 'utf8');
206
-
207
- const result = await terserMinify(content, {
208
- compress: false,
209
- mangle: false,
210
- format: {
211
- comments: false,
212
- beautify: false,
213
- indent_level: 0
214
- }
215
- });
216
-
217
- if (result.error) {
218
- throw new Error(`Terser error in components.js: ${result.error}`);
219
- }
220
-
221
- await fs.writeFile(distPath, result.code, 'utf8');
222
-
223
- const minifiedSize = Buffer.byteLength(result.code, 'utf8');
224
- const savings = Math.round(((originalSize - minifiedSize) / originalSize) * 100);
225
-
226
- Print.minificationResult(`${path.basename(srcPath)} (preserved structure)`, originalSize, minifiedSize, savings);
227
- }
228
-
229
- /**
230
- * Minifies JavaScript files preserving Slice.js architecture
231
- */
232
- async function minifyJavaScript(srcPath, distPath) {
233
- const content = await fs.readFile(srcPath, 'utf8');
234
- const originalSize = Buffer.byteLength(content, 'utf8');
235
-
236
- const result = await terserMinify(content, {
237
- compress: {
238
- drop_console: false,
239
- drop_debugger: true,
240
- pure_funcs: [],
241
- passes: 1,
242
- unused: false,
243
- side_effects: false,
244
- reduce_vars: false,
245
- collapse_vars: false
246
- },
247
- mangle: {
248
- reserved: [
249
- // Core Slice
250
- 'slice', 'Slice', 'SliceJS', 'window', 'document',
251
- // Main classes
252
- 'Controller', 'StylesManager', 'Router', 'Logger', 'Debugger',
253
- // Slice methods
254
- 'getClass', 'isProduction', 'getComponent', 'build', 'setTheme', 'attachTemplate',
255
- // Controller
256
- 'componentCategories', 'templates', 'classes', 'requestedStyles', 'activeComponents',
257
- 'registerComponent', 'registerComponentsRecursively', 'loadTemplateToComponent',
258
- 'fetchText', 'setComponentProps', 'verifyComponentIds', 'destroyComponent',
259
- // StylesManager
260
- 'componentStyles', 'themeManager', 'init', 'appendComponentStyles', 'registerComponentStyles',
261
- // Router
262
- 'routes', 'pathToRouteMap', 'activeRoute', 'navigate', 'matchRoute', 'handleRoute',
263
- 'onRouteChange', 'loadInitialRoute', 'renderRoutesComponentsInPage',
264
- // Propiedades de componentes
265
- 'sliceId', 'sliceType', 'sliceConfig', 'debuggerProps', 'parentComponent',
266
- 'value', 'customColor', 'icon', 'layout', 'view', 'items', 'columns', 'rows',
267
- 'onClickCallback', 'props',
268
- // Custom Elements
269
- 'customElements', 'define', 'HTMLElement',
270
- // Critical DOM APIs
271
- 'addEventListener', 'removeEventListener', 'querySelector', 'querySelectorAll',
272
- 'appendChild', 'removeChild', 'innerHTML', 'textContent', 'style', 'classList',
273
- // Lifecycle
274
- 'beforeMount', 'afterMount', 'beforeDestroy', 'afterDestroy',
275
- 'mount', 'unmount', 'destroy', 'update', 'start', 'stop',
276
- // Browser APIs
277
- 'fetch', 'setTimeout', 'clearTimeout', 'localStorage', 'history', 'pushState',
278
- // Exports/Imports
279
- 'default', 'export', 'import', 'from', 'await', 'async',
280
- // Nombres de componentes
281
- 'Button', 'Grid', 'Layout', 'HomePage', 'NotFound', 'Loading', 'TreeView', 'Link',
282
- 'FetchManager'
283
- ],
284
- properties: { regex: /^_/ }
285
- },
286
- format: {
287
- comments: false,
288
- beautify: false
289
- },
290
- keep_fnames: true,
291
- keep_classnames: true
292
- });
293
-
294
- if (result.error) {
295
- throw new Error(`Terser error: ${result.error}`);
296
- }
297
-
298
- await fs.writeFile(distPath, result.code, 'utf8');
299
-
300
- const minifiedSize = Buffer.byteLength(result.code, 'utf8');
301
- const savings = Math.round(((originalSize - minifiedSize) / originalSize) * 100);
302
-
303
- Print.minificationResult(path.basename(srcPath), originalSize, minifiedSize, savings);
304
- }
305
-
306
- /**
307
- * Minifies CSS files
308
- */
309
- async function minifyCSS(srcPath, distPath) {
310
- const content = await fs.readFile(srcPath, 'utf8');
311
- const originalSize = Buffer.byteLength(content, 'utf8');
312
-
313
- const cleanCSS = new CleanCSS({
314
- level: 2,
315
- returnPromise: false
316
- });
317
-
318
- const result = cleanCSS.minify(content);
319
-
320
- if (result.errors.length > 0) {
321
- throw new Error(`CleanCSS errors: ${result.errors.join(', ')}`);
322
- }
323
-
324
- await fs.writeFile(distPath, result.styles, 'utf8');
325
-
326
- const minifiedSize = Buffer.byteLength(result.styles, 'utf8');
327
- const savings = Math.round(((originalSize - minifiedSize) / originalSize) * 100);
328
-
329
- Print.minificationResult(path.basename(srcPath), originalSize, minifiedSize, savings);
330
- }
331
-
332
- /**
333
- * Minifies HTML files
334
- */
335
- async function minifyHTML(srcPath, distPath) {
336
- const content = await fs.readFile(srcPath, 'utf8');
337
- const originalSize = Buffer.byteLength(content, 'utf8');
338
-
339
- const minified = await minify(content, {
340
- collapseWhitespace: true,
341
- removeComments: true,
342
- removeRedundantAttributes: true,
343
- removeScriptTypeAttributes: true,
344
- removeStyleLinkTypeAttributes: true,
345
- useShortDoctype: true,
346
- minifyCSS: true,
347
- minifyJS: {
348
- mangle: {
349
- reserved: ['slice', 'Slice', 'SliceJS', 'sliceId', 'sliceConfig']
350
- }
351
- },
352
- ignoreCustomFragments: [
353
- /slice-[\w-]+="[^"]*"/g
354
- ]
355
- });
356
-
357
- await fs.writeFile(distPath, minified, 'utf8');
358
-
359
- const minifiedSize = Buffer.byteLength(minified, 'utf8');
360
- const savings = Math.round(((originalSize - minifiedSize) / originalSize) * 100);
361
-
362
- Print.minificationResult(path.basename(srcPath), originalSize, minifiedSize, savings);
363
- }
364
-
365
- /**
366
- * Creates an optimized bundle of the main file
367
- */
368
- async function createOptimizedBundle() {
369
- Print.buildProgress('Creating optimized bundle...');
370
-
371
- const mainJSPath = getDistPath(import.meta.url, 'App', 'index.js');
372
-
373
- if (await fs.pathExists(mainJSPath)) {
374
- Print.success('Main bundle optimized');
375
- } else {
376
- Print.warning('No main JavaScript file found for bundling');
377
- }
378
- }
379
-
380
- /**
381
- * Generates build statistics
382
- */
383
- async function generateBuildStats(srcDir, distDir) {
384
- Print.buildProgress('Generating build statistics...');
385
-
386
- const getDirectorySize = async (dirPath) => {
387
- let totalSize = 0;
388
- const items = await fs.readdir(dirPath);
389
-
390
- for (const item of items) {
391
- const itemPath = path.join(dirPath, item);
392
- const stat = await fs.stat(itemPath);
393
-
394
- if (stat.isDirectory()) {
395
- totalSize += await getDirectorySize(itemPath);
396
- } else {
397
- totalSize += stat.size;
398
- }
399
- }
400
-
401
- return totalSize;
402
- };
403
-
404
- try {
405
- const srcSize = await getDirectorySize(srcDir);
406
- const distSize = await getDirectorySize(distDir);
407
- const savings = Math.round(((srcSize - distSize) / srcSize) * 100);
408
-
409
- Print.newLine();
410
- Print.info(`📊 Build Statistics:`);
411
- console.log(` Source: ${(srcSize / 1024).toFixed(1)} KB`);
412
- console.log(` Built: ${(distSize / 1024).toFixed(1)} KB`);
413
- console.log(` Saved: ${savings}% smaller`);
414
-
415
- } catch (error) {
416
- Print.warning('Could not generate build statistics');
417
- }
418
- }
419
-
420
- /**
421
- * Analyzes the build without building
422
- */
423
- async function analyzeBuild() {
424
- const distDir = getDistPath(import.meta.url);
425
-
426
- if (!await fs.pathExists(distDir)) {
427
- Print.error('No build found to analyze. Run "slice build" first.');
428
- return;
429
- }
430
-
431
- Print.info('Analyzing production build...');
432
- await generateBuildStats(
433
- getSrcPath(import.meta.url),
434
- distDir
435
- );
436
- }
437
-
438
- /**
439
- * MAIN BUILD FUNCTION
440
- */
441
- export default async function buildProduction(options = {}) {
442
- const startTime = Date.now();
443
- const packageManager = resolvePackageManager(getProjectRoot(import.meta.url)).name;
444
-
445
- try {
446
- Print.title('🔨 Building Slice.js project for production...');
447
- Print.newLine();
448
-
449
- const srcDir = getSrcPath(import.meta.url);
450
- const distDir = getDistPath(import.meta.url);
451
-
452
- if (!await fs.pathExists(srcDir)) {
453
- throw new Error('Source directory not found. Run "slice init" first.');
454
- }
455
-
456
- await verifySliceFiles(srcDir);
457
-
458
- // Clean dist directory
459
- if (await fs.pathExists(distDir)) {
460
- if (!options.skipClean) {
461
- Print.info('Cleaning previous build...');
462
- await fs.remove(distDir);
463
- Print.success('Previous build cleaned');
464
- }
465
- }
466
-
467
- await fs.ensureDir(distDir);
468
- await copySliceConfig();
469
-
470
- // Process files
471
- Print.info('Processing and optimizing source files for Slice.js...');
472
- await processDirectory(srcDir, distDir, srcDir, options);
473
- Print.success('All source files processed and optimized');
474
-
475
- await verifyBuildIntegrity(distDir);
476
- await createOptimizedBundle();
477
- await generateBuildStats(srcDir, distDir);
478
-
479
- const buildTime = ((Date.now() - startTime) / 1000).toFixed(1);
480
-
481
- Print.newLine();
482
- Print.success(`✨ Slice.js production build completed in ${buildTime}s`);
483
- Print.info('Your optimized project is ready in the /dist directory');
484
- Print.newLine();
485
- Print.info('Next steps:');
486
- console.log(` • Use "${runScriptCommand(packageManager, 'start')}" to test the production build`);
487
- console.log(' • All Slice.js components and architecture preserved');
488
-
489
- return true;
490
-
491
- } catch (error) {
492
- Print.error(`Build failed: ${error.message}`);
493
- return false;
494
- }
495
- }
496
-
497
- /**
498
- * Preview server for testing the production build
499
- */
500
- export async function serveProductionBuild(port) {
501
- try {
502
- const packageManager = resolvePackageManager(getProjectRoot(import.meta.url)).name;
503
- const config = loadConfig();
504
- const defaultPort = config?.server?.port || 3001;
505
- const finalPort = port || defaultPort;
506
-
507
- const distDir = getDistPath(import.meta.url);
508
-
509
- if (!await fs.pathExists(distDir)) {
510
- throw new Error('No production build found. Run "slice build" first.');
511
- }
512
-
513
- Print.info(`Starting production preview server on port ${finalPort}...`);
514
-
515
- const express = await import('express');
516
- const app = express.default();
517
-
518
- app.use(express.default.static(distDir));
519
-
520
- app.get('*', (req, res) => {
521
- const indexPath = path.join(distDir, 'App/index.html');
522
- const fallbackPath = path.join(distDir, 'index.html');
523
-
524
- if (fs.existsSync(indexPath)) {
525
- res.sendFile(indexPath);
526
- } else if (fs.existsSync(fallbackPath)) {
527
- res.sendFile(fallbackPath);
528
- } else {
529
- res.status(404).send('Production build index.html not found');
530
- }
531
- });
532
-
533
- app.listen(finalPort, () => {
534
- Print.success(`Production preview server running at http://localhost:${finalPort}`);
535
- Print.info('Press Ctrl+C to stop the server');
536
- Print.info('This server previews your production build from /dist');
537
- Print.warning(`This is a preview server - use "${runScriptCommand(packageManager, 'start')}" for the full production server`);
538
- });
539
-
540
- } catch (error) {
541
- Print.error(`Error starting production preview server: ${error.message}`);
542
- throw error;
543
- }
544
- }
545
-
546
- /**
547
- * Build command with options
548
- */
549
- export async function buildCommand(options = {}) {
550
- const config = loadConfig();
551
- const defaultPort = config?.server?.port || 3001;
552
-
553
- if (!await checkBuildDependencies()) {
554
- return false;
555
- }
556
-
557
- if (options.serve) {
558
- await serveProductionBuild(options.port || defaultPort);
559
- return true;
560
- }
561
-
562
- if (options.analyze) {
563
- await analyzeBuild();
564
- return true;
565
- }
566
-
567
- const success = await buildProduction(options);
568
-
569
- if (success && options.preview) {
570
- Print.newLine();
571
- Print.info('✨ Build completed successfully!');
572
- Print.info(`Starting preview server on port ${options.port || defaultPort}...`);
573
- await serveProductionBuild(options.port || defaultPort);
574
- }
575
-
576
- return success;
577
- }