warn('Warning: Building production assets in development mode.'); $this->line('Assets will be built but will not be used until you switch modes:'); $this->line(' php artisan rsx:mode:set debug'); $this->line(' php artisan rsx:mode:set production'); $this->newLine(); } $this->info('Building production assets...'); $this->newLine(); $start_time = microtime(true); // Step 1: Rebuild manifest $this->line('[1/3] Building manifest...'); try { // Enable force build mode to allow rebuilding in production-like modes Manifest::$_force_build = true; // Force a fresh manifest rebuild by clearing and re-initializing Manifest::clear(); Manifest::init(); $this->line(' Manifest built successfully'); } catch (Exception $e) { $this->error(' Failed to build manifest: ' . $e->getMessage()); return 1; } finally { Manifest::$_force_build = false; } // Step 2: Compile all bundles $this->line('[2/3] Compiling bundles...'); // Force restart minify server to pick up any code changes if (Rsx::is_production()) { Minifier::force_restart(); } $manifest_data = Manifest::get_all(); $bundle_classes = []; foreach ($manifest_data as $file_info) { $class_name = $file_info['class'] ?? null; if ($class_name && Manifest::php_is_subclass_of($class_name, 'Rsx_Module_Bundle_Abstract')) { $fqcn = $file_info['fqcn'] ?? $class_name; $bundle_classes[$fqcn] = $class_name; } } if (empty($bundle_classes)) { $this->warn(' No bundles found in manifest'); } else { // Ensure storage directory exists $bundle_dir = storage_path('rsx-build/bundles'); if (!is_dir($bundle_dir)) { mkdir($bundle_dir, 0755, true); } $compiled_count = 0; $failed_bundles = []; foreach ($bundle_classes as $fqcn => $class_name) { $this->line(" Compiling: {$class_name}"); try { $compiler = new BundleCompiler(); $compiled = $compiler->compile($fqcn, ['force_build' => true]); // Get output file info (always vendor/app split) $js_size = 0; $css_size = 0; if (isset($compiled['vendor_js_bundle_path'])) { $js_size += filesize("{$bundle_dir}/{$compiled['vendor_js_bundle_path']}"); } if (isset($compiled['app_js_bundle_path'])) { $js_size += filesize("{$bundle_dir}/{$compiled['app_js_bundle_path']}"); } if (isset($compiled['vendor_css_bundle_path'])) { $css_size += filesize("{$bundle_dir}/{$compiled['vendor_css_bundle_path']}"); } if (isset($compiled['app_css_bundle_path'])) { $css_size += filesize("{$bundle_dir}/{$compiled['app_css_bundle_path']}"); } $this->line(' JS: ' . $this->_format_size($js_size) . ', CSS: ' . $this->_format_size($css_size)); $compiled_count++; } catch (Exception $e) { $this->error(" Failed: {$e->getMessage()}"); $failed_bundles[$class_name] = $e->getMessage(); } } if (!empty($failed_bundles)) { $this->error(" {$compiled_count} compiled, " . count($failed_bundles) . ' failed'); return 1; } $this->line(" {$compiled_count} bundles compiled"); } // Step 3: Laravel caches if (!$this->option('skip-laravel-cache')) { $this->line('[3/3] Building Laravel caches...'); passthru('php artisan optimize:cache 2>/dev/null', $exit_code); if ($exit_code === 0) { $this->line(' Laravel caches built'); } } else { $this->line('[3/3] Skipping Laravel caches (--skip-laravel-cache)'); } $elapsed = round(microtime(true) - $start_time, 2); $this->newLine(); $this->info("[OK] Production build complete ({$elapsed}s)"); if (Rsx::is_development()) { $this->newLine(); $this->line('To use these assets, switch to production mode:'); $this->line(' php artisan rsx:mode:set production'); } return 0; } private function _format_size(int $bytes): string { if ($bytes < 1024) { return "{$bytes} B"; } if ($bytes < 1048576) { return round($bytes / 1024, 1) . ' KB'; } return round($bytes / 1048576, 2) . ' MB'; } }