alizharb/laravel-themer
Enterprise-grade theme management for Laravel. Create, clone, activate, and safely delete themes with per-theme Vite builds, NPM workspaces, asset shortcuts, view overrides, and Livewire 4 support. Includes metadata, wizards, and fast production caching.
Best practices for deploying Laravel Themer applications to production.
php artisan theme:build mytheme
This compiles and minifies all CSS and JavaScript files.
php artisan theme:cache
This creates bootstrap/cache/themes.php for faster theme loading.
php artisan theme:publish
Ensure all theme assets are in the public directory.
php artisan config:cache
php artisan route:cache
php artisan view:cache
.envAPP_ENV=production
APP_DEBUG=false
# Active theme
THEME=mytheme
# Disable symlinks in production
THEMER_SYMLINK=false
In config/themer.php:
'assets' => [
'publish_on_activate' => false,
'symlink' => false,
],
#!/bin/bash
# Pull latest code
git pull origin main
# Install dependencies
composer install --no-dev --optimize-autoloader
npm install --production
# Build theme assets
php artisan theme:build mytheme
# Publish theme assets
php artisan theme:publish
# Cache everything
php artisan theme:cache
php artisan config:cache
php artisan route:cache
php artisan view:cache
# Restart services
php artisan queue:restart
#!/bin/bash
# Use Laravel Envoy or Deployer
# Example with Envoy:
[@servers](https://github.com/servers)(['production' => 'user@server'])
[@task](https://github.com/task)('deploy', ['on' => 'production'])
cd /var/www/app
# Maintenance mode
php artisan down
# Update code
git pull origin main
# Dependencies
composer install --no-dev --optimize-autoloader
npm ci --production
# Build assets
php artisan theme:build mytheme
php artisan theme:publish
# Cache
php artisan theme:cache
php artisan config:cache
php artisan route:cache
php artisan view:cache
# Migrations
php artisan migrate --force
# Exit maintenance
php artisan up
# Restart services
php artisan queue:restart
[@endtask](https://github.com/endtask)
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: '20'
- name: Install Dependencies
run: |
composer install --no-dev --optimize-autoloader
npm ci --production
- name: Build Theme Assets
run: php artisan theme:build mytheme
- name: Run Tests
run: php artisan test
- name: Deploy to Production
run: |
# Your deployment script
./deploy.sh
Use tools like spatie/image-optimizer:
composer require spatie/image-optimizer
use Spatie\ImageOptimizer\OptimizerChainFactory;
$optimizerChain = OptimizerChainFactory::create();
$optimizerChain->optimize(get_active_theme()->path . '/resources/assets/images/hero.jpg');
Tailwind CSS 4 uses a config-less approach with [@theme](https://github.com/theme) directive:
themes/mytheme/resources/assets/css/app.css:
[@import](https://github.com/import) "tailwindcss";
[@theme](https://github.com/theme) {
--color-primary: oklch(60% 0.20 280);
--color-secondary: oklch(70% 0.16 280);
}
[@layer](https://github.com/layer) components {
.btn-primary {
background: var(--color-primary);
color: white;
padding: 0.5rem 1rem;
border-radius: 0.5rem;
}
}
Content paths are automatically detected from your imports. No configuration file needed!
Vite automatically minifies in production builds.
In .env:
ASSET_URL=https://cdn.example.com
# After building
php artisan theme:build mytheme
# Sync to S3/CloudFront
aws s3 sync public/themes/mytheme s3://your-bucket/themes/mytheme --delete
composer require laravel/telescope --dev
php artisan telescope:install
Monitor theme asset loading and view rendering times.
Track theme-specific metrics:
// In ThemeServiceProvider
public function boot()
{
if (app()->environment('production')) {
newrelic_add_custom_parameter('theme', get_active_theme()->slug);
}
}
Only install themes from trusted sources.
If allowing user theme selection:
public function switchTheme(Request $request)
{
$theme = $request->input('theme');
if (!app('themer')->find($theme)) {
abort(404);
}
// Validate against whitelist
$allowed = ['default', 'dark', 'light'];
if (!in_array($theme, $allowed)) {
abort(403);
}
session(['theme' => $theme]);
}
Ensure theme directories are not writable by web server:
chmod -R 755 themes/
Configure CSP headers for theme assets:
// In middleware
$response->headers->set('Content-Security-Policy',
"default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self'"
);
# Clear all caches
php artisan cache:clear
php artisan config:clear
php artisan view:clear
php artisan theme:clear
# Republish assets
php artisan theme:publish --force
# Check theme discovery
php artisan theme:list
# Validate theme structure
php artisan theme:check mytheme
# Rebuild cache
php artisan theme:cache
# Enable query logging
DB::enableQueryLog();
# Check for N+1 queries
php artisan telescope:prune
# Profile asset loading
php artisan debugbar:clear
# Revert to previous theme
php artisan theme:activate previous-theme
# Clear caches
php artisan cache:clear
php artisan view:clear
# Revert code
git revert HEAD
# Rebuild assets
php artisan theme:build old-theme
php artisan theme:publish
# Clear caches
php artisan theme:cache
php artisan config:cache
// routes/web.php
Route::get('/health', function () {
return response()->json([
'status' => 'ok',
'theme' => get_active_theme()?->slug,
'version' => get_active_theme()?->version,
]);
});
Use Sentry or Bugsnag to track theme-related errors:
if ($exception instanceof ThemeNotFoundException) {
Sentry::captureException($exception);
}
Never deploy without building theme assets.
Vite handles this automatically via content hashing.
Always test theme changes in a staging environment first.
Track theme asset load times and rendering performance.
Always be able to quickly revert to the previous theme.
How can I help you explore Laravel packages today?