Standardize settings file naming and relocate documentation files Fix code quality violations from rsx:check Reorganize user_management directory into logical subdirectories Move Quill Bundle to core and align with Tom Select pattern Simplify Site Settings page to focus on core site information Complete Phase 5: Multi-tenant authentication with login flow and site selection Add route query parameter rule and synchronize filename validation logic Fix critical bug in UpdateNpmCommand causing missing JavaScript stubs Implement filename convention rule and resolve VS Code auto-rename conflict Implement js-sanitizer RPC server to eliminate 900+ Node.js process spawns Implement RPC server architecture for JavaScript parsing WIP: Add RPC server infrastructure for JS parsing (partial implementation) Update jqhtml terminology from destroy to stop, fix datagrid DOM preservation Add JQHTML-CLASS-01 rule and fix redundant class names Improve code quality rules and resolve violations Remove legacy fatal error format in favor of unified 'fatal' error type Filter internal keys from window.rsxapp output Update button styling and comprehensive form/modal documentation Add conditional fly-in animation for modals Fix non-deterministic bundle compilation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
440 lines
14 KiB
Plaintext
Executable File
440 lines
14 KiB
Plaintext
Executable File
BUNDLE_API(3) RSX Framework Manual BUNDLE_API(3)
|
|
|
|
NAME
|
|
Bundle - RSX asset compilation and management system
|
|
|
|
SYNOPSIS
|
|
use App\RSpade\Core\Bundle\Rsx_Bundle_Abstract;
|
|
|
|
class My_Bundle extends Rsx_Bundle_Abstract
|
|
{
|
|
public static function define(): array
|
|
{
|
|
return [
|
|
'include' => [
|
|
'jquery', // Module alias
|
|
'Bootstrap5_Bundle', // Bundle class
|
|
'rsx/app/myapp', // Directory
|
|
'rsx/lib/utils.js', // Specific file
|
|
],
|
|
];
|
|
}
|
|
}
|
|
|
|
// Render in Blade
|
|
{!! My_Bundle::render() !!}
|
|
|
|
DESCRIPTION
|
|
RSX Bundles provide a radically simplified asset compilation system
|
|
compared to Laravel Mix or Vite. Instead of webpack configurations,
|
|
JSON manifests, and build scripts, you define a simple PHP class
|
|
with an array of what to include. The framework handles everything
|
|
else automatically.
|
|
|
|
Unlike Laravel's approach where you configure webpack, define entry
|
|
points, set up hot module replacement, and manage complex build
|
|
pipelines, RSX Bundles use a single 'include' array that accepts
|
|
any mix of directories, files, NPM packages, or other bundles.
|
|
The system automatically determines file types, resolves dependencies,
|
|
and compiles everything.
|
|
|
|
The Bundle system integrates directly with the Manifest, automatically
|
|
including JavaScript stubs for controllers and models. SCSS files are
|
|
compiled transparently. Vendor and application code are automatically
|
|
split for optimal caching.
|
|
|
|
Key differences from Laravel Mix/Vite:
|
|
- Laravel: Complex webpack.mix.js or vite.config.js files
|
|
- RSX: Simple PHP class with an include array
|
|
|
|
- Laravel: Manual configuration of entry points and outputs
|
|
- RSX: Automatic detection and compilation
|
|
|
|
- Laravel: Separate processes for JS bundling and CSS compilation
|
|
- RSX: Unified system handles all asset types
|
|
|
|
- Laravel: Manual versioning and cache busting setup
|
|
- RSX: Automatic hash-based cache busting
|
|
|
|
Benefits:
|
|
- No JavaScript build configuration needed
|
|
- Works immediately without npm run dev/build
|
|
- Automatic vendor/app code splitting
|
|
- Integrated with PHP class discovery
|
|
- Zero configuration SCSS compilation
|
|
|
|
CREATING A BUNDLE
|
|
1. Extend Rsx_Bundle_Abstract
|
|
2. Implement define() method
|
|
3. Return configuration array with 'include' key
|
|
|
|
Example:
|
|
class Dashboard_Bundle extends Rsx_Bundle_Abstract
|
|
{
|
|
public static function define(): array
|
|
{
|
|
return [
|
|
'include' => [
|
|
'jquery',
|
|
'lodash',
|
|
'bootstrap5',
|
|
'rsx/app/dashboard',
|
|
],
|
|
'config' => [
|
|
'api_version' => '2.0',
|
|
],
|
|
];
|
|
}
|
|
}
|
|
|
|
BUNDLE PLACEMENT
|
|
Bundles exist ONLY at the top-level module directory. Never create
|
|
bundles in subdirectories or submodules.
|
|
|
|
CORRECT:
|
|
/rsx/app/login/login_bundle.php ✓ Top-level module
|
|
/rsx/app/dashboard/dashboard_bundle.php ✓ Top-level module
|
|
/rsx/app/frontend/frontend_bundle.php ✓ Top-level module
|
|
|
|
INCORRECT:
|
|
/rsx/app/login/accept_invite/accept_invite_bundle.php ✗ Subdirectory
|
|
/rsx/app/frontend/settings/settings_bundle.php ✗ Submodule
|
|
/rsx/app/frontend/users/edit/edit_bundle.php ✗ Feature
|
|
|
|
WHY TOP-LEVEL ONLY:
|
|
Including __DIR__ in a top-level bundle automatically includes all
|
|
files in that module directory and all subdirectories recursively.
|
|
This provides complete coverage without needing multiple bundles.
|
|
|
|
Example:
|
|
// /rsx/app/login/login_bundle.php
|
|
class Login_Bundle extends Rsx_Bundle_Abstract
|
|
{
|
|
public static function define(): array
|
|
{
|
|
return [
|
|
'include' => [
|
|
__DIR__, // Includes ALL of /rsx/app/login/ recursively
|
|
],
|
|
];
|
|
}
|
|
}
|
|
|
|
This single bundle covers:
|
|
/rsx/app/login/login_controller.php
|
|
/rsx/app/login/login_index.blade.php
|
|
/rsx/app/login/login_index.js
|
|
/rsx/app/login/accept_invite/accept_invite_controller.php
|
|
/rsx/app/login/accept_invite/accept_invite.blade.php
|
|
/rsx/app/login/accept_invite/accept_invite.js
|
|
/rsx/app/login/accept_invite/create_account.blade.php
|
|
/rsx/app/login/accept_invite/create_account.js
|
|
/rsx/app/login/signup/...
|
|
... and all other files in subdirectories
|
|
|
|
The __DIR__ constant resolves to the bundle's directory, making it
|
|
self-referential and automatically including all module content.
|
|
|
|
INCLUDE TYPES
|
|
Module Aliases
|
|
Predefined in config/rsx.php:
|
|
'jquery', 'lodash', 'bootstrap5', 'vue', 'react'
|
|
|
|
Bundle Classes
|
|
Reference other bundles:
|
|
'Core_Bundle', 'Bootstrap5_Src_Bundle'
|
|
|
|
Bundle Aliases
|
|
Defined in config/rsx.php:
|
|
'bootstrap5_src' => Bootstrap5_Src_Bundle::class
|
|
|
|
Directories
|
|
Include all files recursively:
|
|
'rsx/app/dashboard'
|
|
|
|
Specific Files
|
|
Include individual files:
|
|
'rsx/lib/utils.js'
|
|
'rsx/theme/variables.scss'
|
|
|
|
NPM Modules
|
|
Include from node_modules:
|
|
'npm:axios'
|
|
'npm:moment'
|
|
|
|
CDN Assets
|
|
External resources:
|
|
'cdn:https://unpkg.com/library.js'
|
|
|
|
Public Directory Assets
|
|
Static assets from public/ directories with automatic cache-busting:
|
|
'/public/sneat/css/core.css'
|
|
'/public/sneat/js/helpers.js'
|
|
|
|
These resolve to files in any public/ directory in rsx/. Resolution
|
|
cached in Redis for performance. Generates tags with filemtime() for
|
|
fresh cache-busting on each page render.
|
|
|
|
PUBLIC ASSET INCLUDES
|
|
Bundles can include static assets from any public/ directory with
|
|
automatic cache-busting via filemtime().
|
|
|
|
SYNTAX
|
|
Prefix paths with /public/ in bundle includes:
|
|
|
|
'include' => [
|
|
'/public/sneat/css/core.css',
|
|
'/public/sneat/js/helpers.js',
|
|
]
|
|
|
|
RESOLUTION
|
|
Path "sneat/css/demo.css" resolves to first match across all public/
|
|
directories in manifest. Resolution cached in Redis indefinitely.
|
|
|
|
Searches:
|
|
rsx/public/sneat/css/demo.css
|
|
rsx/app/admin/public/sneat/css/demo.css
|
|
rsx/theme/public/sneat/css/demo.css
|
|
... (all public/ directories)
|
|
|
|
OUTPUT
|
|
CSS: <link rel="stylesheet" href="/sneat/css/demo.css?v={filemtime}">
|
|
JS: <script src="/sneat/js/helpers.js?v={filemtime}" defer></script>
|
|
|
|
The filemtime() call executes on each page render, providing fresh
|
|
cache-busting timestamps without rebuilding bundles.
|
|
|
|
ORDERING
|
|
Public assets output with CDN includes, before compiled bundle code.
|
|
Order preserved as listed in bundle definition:
|
|
|
|
1. CDN CSS assets
|
|
2. Public directory CSS
|
|
3. Compiled bundle CSS
|
|
4. CDN JS assets
|
|
5. Public directory JS
|
|
6. Compiled bundle JS
|
|
|
|
AMBIGUITY ERRORS
|
|
If multiple files match the same path, compilation fails:
|
|
|
|
RuntimeException: Ambiguous public asset request:
|
|
'sneat/css/demo.css' matches multiple files:
|
|
'rsx/public/sneat/css/demo.css',
|
|
'rsx/theme/public/sneat/css/demo.css'
|
|
|
|
Solution: Use more specific paths or rename files to avoid conflicts.
|
|
|
|
CACHING
|
|
- Path resolution cached in Redis indefinitely
|
|
- Cache validated on each use (file existence check)
|
|
- Stale cache automatically re-scanned
|
|
- filemtime() executes on each page render for cache-busting
|
|
|
|
RESTRICTIONS
|
|
- Only .js and .css files allowed
|
|
- Must start with /public/ prefix
|
|
- Files must exist in a public/ directory
|
|
- No PHP files allowed (security)
|
|
|
|
BUNDLE RENDERING
|
|
In Blade layouts/views:
|
|
{!! Dashboard_Bundle::render() !!}
|
|
|
|
Generates:
|
|
<link href="/bundles/Dashboard__vendor.abc123.css" rel="stylesheet">
|
|
<link href="/bundles/Dashboard__app.def456.css" rel="stylesheet">
|
|
<script src="/bundles/Dashboard__vendor.abc123.js"></script>
|
|
<script src="/bundles/Dashboard__app.def456.js"></script>
|
|
|
|
Never call from controllers - only from Blade files.
|
|
|
|
VENDOR/APP SPLIT
|
|
Files automatically split:
|
|
- vendor/: Files containing "vendor/" in path, NPM modules
|
|
- app/: Everything else
|
|
|
|
Benefits:
|
|
- Vendor files cached longer (rarely change)
|
|
- App files rebuilt on changes
|
|
- Smaller incremental builds
|
|
|
|
BUNDLE PROCESSORS
|
|
Transform files during compilation.
|
|
Configured globally in config/rsx.php.
|
|
|
|
Built-in processors:
|
|
- ScssProcessor: .scss → .css
|
|
- JqhtmlProcessor: .jqhtml → JavaScript
|
|
|
|
All processors receive ALL collected files,
|
|
decide what to process based on extension.
|
|
|
|
CREATING A PROCESSOR
|
|
class MyProcessor extends AbstractBundleProcessor
|
|
{
|
|
public static function get_name(): string
|
|
{
|
|
return 'myprocessor';
|
|
}
|
|
|
|
public static function get_extensions(): array
|
|
{
|
|
return ['myext']; // Extensions to process
|
|
}
|
|
|
|
public static function process(string $file, array $options = []): ?array
|
|
{
|
|
$content = file_get_contents($file);
|
|
|
|
// Transform content
|
|
$processed = transform($content);
|
|
|
|
return [
|
|
'content' => $processed,
|
|
'extension' => 'js', // Output extension
|
|
];
|
|
}
|
|
}
|
|
|
|
Register in config/rsx.php:
|
|
'bundle_processors' => [
|
|
App\RSpade\Processors\MyProcessor::class,
|
|
],
|
|
|
|
COMPILATION PROCESS
|
|
1. Resolve all includes to file list
|
|
2. Split into vendor/app buckets
|
|
3. Check cache (skip if unchanged)
|
|
4. Run processors on files
|
|
5. Add JavaScript stubs from manifest
|
|
6. Filter to JS/CSS only
|
|
7. Compile vendor and app separately
|
|
8. In production: concatenate into single files
|
|
|
|
JAVASCRIPT STUBS
|
|
Controllers with Ajax_Endpoint methods get stubs:
|
|
// Automatically included in bundles
|
|
class User_Controller {
|
|
static async get_profile(...args) {
|
|
return Ajax.call(Rsx.Route('User_Controller', 'get_profile'), args);
|
|
}
|
|
}
|
|
|
|
Note: Rsx.Route() generates type-safe URLs like /_ajax/User_Controller/get_profile
|
|
|
|
Models with fetch() methods get stubs:
|
|
class User_Model {
|
|
static async fetch(id) {
|
|
return Ajax.model_fetch('User_Model', id);
|
|
}
|
|
}
|
|
|
|
CONFIGURATION
|
|
Bundle config added to window.rsxapp:
|
|
'config' => [
|
|
'feature_flags' => ['new_ui'],
|
|
'api_version' => '2.0',
|
|
]
|
|
|
|
Access in JavaScript:
|
|
if (window.rsxapp.config.feature_flags.includes('new_ui')) {
|
|
// New UI code
|
|
}
|
|
|
|
CACHING
|
|
Development:
|
|
- Vendor files cached until dependencies change
|
|
- App files rebuilt on any change
|
|
- Cache keys based on file hashes
|
|
|
|
Production:
|
|
- All files concatenated and minified
|
|
- Cache forever with hash in filename
|
|
- Rebuild only via rsx:bundle:compile
|
|
|
|
REQUIRED BUNDLES
|
|
Automatically included if used:
|
|
- jquery (if $ or jQuery detected)
|
|
- lodash (if _ detected)
|
|
- jqhtml (if .jqhtml files present)
|
|
|
|
FILE ORGANIZATION
|
|
storage/rsx-build/bundles/
|
|
├── Dashboard__vendor.abc123.js
|
|
├── Dashboard__vendor.abc123.css
|
|
├── Dashboard__app.def456.js
|
|
└── Dashboard__app.def456.css
|
|
|
|
Hash changes when content changes.
|
|
|
|
EXAMPLES
|
|
// Kitchen sink bundle
|
|
class App_Bundle extends Rsx_Bundle_Abstract
|
|
{
|
|
public static function define(): array
|
|
{
|
|
return [
|
|
'include' => [
|
|
// Required modules
|
|
'jquery',
|
|
'lodash',
|
|
'bootstrap5',
|
|
|
|
// Other bundles
|
|
'Core_Bundle',
|
|
|
|
// Application code
|
|
'rsx/app',
|
|
'rsx/lib',
|
|
|
|
// Specific overrides
|
|
'rsx/theme/variables.scss',
|
|
|
|
// NPM packages
|
|
'npm:axios',
|
|
'npm:chart.js',
|
|
],
|
|
'config' => [
|
|
'app_name' => 'MyApp',
|
|
'version' => '1.0.0',
|
|
],
|
|
];
|
|
}
|
|
}
|
|
|
|
// Module-specific bundle
|
|
class Admin_Bundle extends Rsx_Bundle_Abstract
|
|
{
|
|
public static function define(): array
|
|
{
|
|
return [
|
|
'include' => [
|
|
__DIR__, // Include bundle's directory
|
|
'rsx/lib/admin',
|
|
],
|
|
];
|
|
}
|
|
}
|
|
|
|
CIRCULAR DEPENDENCIES
|
|
Framework detects and prevents circular includes:
|
|
- A includes B, B includes A = error
|
|
- Shows clear error with dependency chain
|
|
|
|
TROUBLESHOOTING
|
|
Bundle not updating:
|
|
php artisan rsx:bundle:compile My_Bundle --force
|
|
|
|
Missing files:
|
|
Check paths are relative to project root.
|
|
Verify files exist in manifest.
|
|
|
|
Processor not running:
|
|
Check processor registered in config.
|
|
Verify file extension matches.
|
|
|
|
SEE ALSO
|
|
manifest_api(3), jqhtml(3), controller(3)
|
|
|
|
RSX Framework 2025-09-17 BUNDLE_API(3) |