Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Export Laravel Package

spatie/laravel-export

Export a Laravel app as a static site bundle. Crawls your routes to generate HTML for every URL and copies your public assets into an export folder, ready to upload to Netlify or any static host—keep Laravel tools locally while deploying static.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation

    composer require spatie/laravel-export
    php artisan vendor:publish --provider="Spatie\Export\ExportServiceProvider"
    

    Publish the config file to customize default paths (config/export.php).

  2. First Export

    php artisan export
    

    Outputs static HTML files to storage/app/export (default) with all crawled routes and the public directory.

  3. Where to Look First

    • Config File: config/export.php (adjust paths, routes, and crawling behavior).
    • Crawler Logic: Override Spatie\Export\Crawler\Crawler in your app for custom route filtering.
    • Artisan Command: app/Console/Kernel.php to bind custom commands or extend the default export command.
  4. First Use Case Export a blog built with Laravel + Filament:

    php artisan export --routes="posts.*,admin.posts.*" --exclude-routes="admin.*"
    

    Generates static HTML for all posts.* routes while excluding admin routes.


Implementation Patterns

Core Workflows

  1. Route-Based Exporting

    • Default Behavior: Crawls all routes defined in routes/web.php (excluding GET routes with middleware('web') by default).
    • Customization:
      // In config/export.php
      'routes' => [
          'include' => ['posts.index', 'about'],
          'exclude' => ['admin.*', 'dashboard'],
      ],
      
    • Dynamic Route Lists: Pass routes via CLI:
      php artisan export --routes="home,blog.*"
      
  2. Asset Handling

    • Automatically copies the entire public directory to the export folder.
    • Custom Assets: Override Spatie\Export\AssetHandler to include additional files (e.g., vendor assets):
      public function handle(): void
      {
          $this->copyDirectory(public_path(), $this->exportPath);
          $this->copyDirectory(base_path('vendor/your-package/public'), $this->exportPath.'/vendor');
      }
      
  3. Caching and Incremental Exports

    • Cache Responses: Use middleware to cache dynamic content (e.g., Spatie\Export\Middleware\CacheResponses) to avoid re-rendering on every export.
    • Incremental Exports: Implement Spatie\Export\Contracts\Exportable to skip unchanged routes:
      public function shouldExport(Request $request): bool
      {
          return !Cache::has("exported_{$request->path()}");
      }
      
  4. Integration with Admin Panels

    • Filament/Nova Example:
      • Export dynamic content (e.g., blog posts) via API routes:
        Route::get('/export-posts', function () {
            return response()->json(Post::all()->toArray());
        })->middleware(['web', 'exportable']); // Custom middleware to allow export
        
      • Use the --api flag to crawl API routes:
        php artisan export --api
        
  5. Local Development to Static Hosting

    • Workflow:
      1. Develop locally with Laravel + admin panel (e.g., Filament).
      2. Export to static files:
        php artisan export --directory=build
        
      3. Deploy build/ to Netlify/Vercel/GitHub Pages.
    • CI/CD Integration:
      # .github/workflows/export.yml
      jobs:
        export:
          runs-on: ubuntu-latest
          steps:
            - uses: actions/checkout@v4
            - run: composer install
            - run: php artisan export --directory=build
            - uses: actions/upload-artifact@v3
              with:
                name: static-site
                path: build/
      

Gotchas and Tips

Pitfalls

  1. Dynamic Content Leaks

    • Issue: Unintended dynamic data (e.g., user-specific content) may leak into static exports.
    • Fix: Use middleware to sanitize or mock data:
      // app/Http/Middleware/ExportSanitizer.php
      public function handle(Request $request, Closure $next)
      {
          if ($request->hasHeader('X-Export')) {
              $request->merge(['user' => User::find(1)]); // Mock user
          }
          return $next($request);
      }
      
    • Register middleware in config/export.php:
      'middleware' => [
          \App\Http\Middleware\ExportSanitizer::class,
      ],
      
  2. Route Crawling Quirks

    • Issue: Nested routes or route model binding may fail during crawling.
    • Fix: Mock dependencies in Spatie\Export\Crawler\Crawler:
      public function resolveRouteBinding(string $parameter, string $value)
      {
          if ($parameter === 'post') {
              return Post::findOrFail(1); // Mock post
          }
          return parent::resolveRouteBinding($parameter, $value);
      }
      
  3. Asset Paths Break

    • Issue: Hardcoded asset paths (e.g., /storage/) fail in static exports.
    • Fix: Use Laravel Mix/Valet/Vite to generate relative paths or configure AssetHandler:
      public function getAssetUrl(string $path): string
      {
          return str_replace(public_path(), '', $path);
      }
      
  4. Database Connections

    • Issue: Exports may fail if the database is unreachable (e.g., in CI).
    • Fix: Use SQLite or a local database for exports:
      php artisan export --database=sqlite_testing
      
    • Configure in config/export.php:
      'database_connection' => env('EXPORT_DB_CONNECTION', 'sqlite_testing'),
      
  5. SEO and Meta Tags

    • Issue: Dynamic meta tags (e.g., OpenGraph) may not render correctly.
    • Fix: Pre-render meta tags in Blade or use a package like spatie/laravel-seo-tools to generate static meta files.

Debugging Tips

  1. Dry Run Mode Use --dry-run to log routes without exporting:

    php artisan export --dry-run
    
  2. Verbose Output Enable debug mode in config/export.php:

    'debug' => env('APP_DEBUG', false),
    
  3. Custom Exporter Class Extend Spatie\Export\Exporters\HtmlExporter to log or validate exports:

    public function exportRoute(Route $route)
    {
        Log::info("Exporting route: {$route->uri}");
        return parent::exportRoute($route);
    }
    
  4. Testing Exports Use Spatie\Export\Testing\TestsExport trait in PHPUnit:

    use Spatie\Export\Testing\TestsExport;
    
    class ExportTest extends TestCase
    {
        use TestsExport;
    
        public function test_export_contains_homepage()
        {
            $this->assertExportedRouteExists('/');
        }
    }
    

Extension Points

  1. Custom Exporters Create a new exporter for non-HTML formats (e.g., PDF):

    class PdfExporter implements Exporter
    {
        public function export(Route $route)
        {
            $pdf = PDF::loadView('pdf.template', ['route' => $route]);
            return $pdf->save(storage_path("export/{$route->uri}.pdf"));
        }
    }
    

    Register in config/export.php:

    'exporters' => [
        \App\Exporters\PdfExporter::class,
    ],
    
  2. Pre/Post Export Hooks Use events to run logic before/after export:

    // In EventServiceProvider
    protected $listen = [
        'export.starting' => [\App\Listeners\BackupDatabase::class],
        'export.finished' => [\App\Listeners\NotifySlack::class],
    ];
    
  3. Custom Crawlers Override Spatie\Export\Crawler\Crawler to implement custom logic (e.g., skip authenticated routes):

    public function shouldCrawl(Route $route): bool
    {
        return !collect($route->middleware())->contains('auth');
    }
    
  4. Static Site Generators Integrate with tools like laravel-static-page-generator or spatie/laravel-static-page-generator for advanced use cases (e.g., Markdown support).

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport