State & Tooling
Control module state, compile manifests, and check compatibility.
Enabled state (storage/modules.json) #
- Created automatically the first time you run
velvet module:enable fooormodule:disable foo. - Structure:
{
"enabled": [
"docs",
"acme-blog"
]
}
- Only modules listed here participate in compilation. Disable a module to keep the code around without loading it.
Compilation artifacts #
| File | Purpose |
|---|---|
storage/modules-compiled.json |
Canonical manifest with load order, entry class, version, requirements. Read at runtime by ModuleManager::load(). |
storage/modules-autoload.php |
Auto-generated PSR-4 mapping used by a single spl_autoload_register for all modules. Keeps bootstrap O(1) even with large module counts. |
velvet module:compile regenerates both files, validates dependencies, and ensures each entry class autoloads.
CLI flow #
module:list– Discover everything (config paths, globbed directories,vendor/*packages of typevelvetcms-module) and print metadata.module:enable foo– Addsfootomodules.json.module:disable fooremoves it.module:compile– Validates enabled modules and writes the compiled manifest/autoloader.- Deploy or reload the app—the bootstrap loads modules via the compiled manifest.
Runtime lifecycle #
ModuleManager::load()readsmodules-compiled.json, registers the shared autoloader, instantiates each entry class, and stores them in$this->modules.register()phase: modules bind services/config.boot()phase: modules register routes, commands, template paths, event listeners.VersionRegistrymerges compiled module metadata intoconfig/version.php, making versions accessible to CLI + HTTP.
Checking compatibility #
VelvetCMS\Core\VersionRegistry exposes helpers:
$registry = VersionRegistry::instance();
$registry->getModules();
$registry->isCompatible('docs', 'core');
$registry->checkModuleRequirements('acme-blog');
The registry reads module requirements from the compiled manifest, so you always compare against the actual enabled set.
Troubleshooting #
- Missing entry class →
module:compilefails withunable to autoload entry class.... Verify namespaces in your module’scomposer.json. - Unsatisfied constraints → upgrade core or dependent modules until
requiresstrings (Composer-style semver constraints) are satisfied. - Modules not loading → ensure
modules-autoload.phpexists and includes the relevant namespace. If it’s missing, rerunmodule:compile. - Hot reload → after changing module PHP files you usually don’t need to recompile (since autoload mapping is unchanged). Recompile when you add/remove modules or change manifest metadata.
With the state + tooling pieces in place, you can safely enable/disable features per environment and verify compatibility before deploys.