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, renders HTML for each discovered URL, and copies the public directory so assets are included. Ideal for blogs and marketing sites hosted on Netlify or any static hosting.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require spatie/laravel-export
    

    No additional configuration is required to start exporting.

  2. First Export:

    php artisan export
    

    This generates a static site bundle in the export directory (default) with all crawled pages and the public folder contents.

  3. Verify Output:

    • Check the export directory for generated HTML files.
    • Ensure assets (CSS, JS, images) from public/ are included.

First Use Case

Export a Blog with Dynamic Content:

  1. Create a blog using Laravel (e.g., with a Post model and routes like /posts/{slug}).
  2. Run php artisan export to generate static HTML for all blog posts.
  3. Deploy the export folder to a static host (e.g., Netlify, S3).

Implementation Patterns

Core Workflow

  1. Crawling:

    • By default, the package crawls all accessible routes in your Laravel app.
    • Disable crawling and manually specify paths in config/export.php:
      'paths' => [
          '/',
          '/posts/{slug}',
          '/about',
      ],
      
    • Dynamically set paths via the Exporter class (e.g., in a service provider):
      $exporter->paths(Post::all()->pluck('slug')->toArray());
      
  2. Asset Handling:

    • Automatically includes the public folder. Customize with:
      'include_files' => [
          'public' => '',
          'custom-assets' => 'assets',
      ],
      
    • Exclude files (e.g., PHP files or mix-manifest.json):
      'exclude_file_patterns' => [
          '/\.php$/',
          '/mix-manifest\.json$/',
      ],
      
  3. Hooks for Automation:

    • Run pre/post-export commands (e.g., asset compilation or deployment):
      'before' => [
          'build-assets' => 'npm run build',
      ],
      'after' => [
          'deploy' => 'netlify deploy --prod',
      ],
      
    • Skip hooks during testing:
      php artisan export --skip-before --skip-after
      
  4. Custom Disks:

    • Store exports in S3, FTP, or a custom directory:
      // config/filesystem.php
      'export' => [
          'driver' => 's3',
          'key' => 'your-key',
          'secret' => 'your-secret',
          'bucket' => 'your-bucket',
      ],
      

Integration Tips

  • Dynamic Routes: Use the Exporter class to dynamically generate paths for resources like blog posts or products:

    $exporter->paths(Post::query()->pluck('slug')->toArray());
    
  • Conditional Exports: Add logic to exclude draft content or private routes:

    $exporter->paths(
        Post::where('published_at', '<=', now())
             ->pluck('slug')
             ->toArray()
    );
    
  • Testing: Mock the Exporter in unit tests to verify paths or hooks:

    $exporter = $this->app->make(Exporter::class);
    $exporter->shouldReceive('paths')->with(['/test']);
    

Gotchas and Tips

Pitfalls

  1. Circular References:

    • Avoid infinite loops in routes (e.g., /posts/{slug} linking to /posts/{slug}/edit). Use exclude_file_patterns or middleware to block admin routes:
      'exclude_file_patterns' => [
          '/admin/',
      ],
      
  2. Asset Paths:

    • Hardcoded asset paths (e.g., /css/style.css) may break in static exports. Use Laravel’s asset() helper or mix-manifest.json for dynamic paths.
  3. Middleware Conflicts:

    • Static exports bypass Laravel middleware (e.g., auth, rate-limiting). Add a header check in middleware:
      if (!$request->header('X-Laravel-Export')) {
          // Apply middleware logic
      }
      
  4. Streaming Memory Issues:

    • Enable streaming for large sites to reduce memory usage:
      'use_streaming' => true,
      
    • Monitor memory during exports with php artisan export --verbose.
  5. Symlinks and Non-Files:

    • Skip symlinks or non-file entries (e.g., directories) by handling exceptions in custom IncludeFile logic or updating the config:
      'exclude_file_patterns' => [
          '/\.php$/',
          '/mix-manifest\.json$/',
          '/\.symlink$/', // Add custom patterns
      ],
      

Debugging Tips

  1. Verbose Output: Run exports with --verbose to debug crawling or file inclusion:

    php artisan export --verbose
    
  2. Dry Runs: Test paths without writing files by temporarily changing the disk to null:

    // config/filesystem.php
    'export' => [
        'driver' => 'null',
    ],
    
  3. Hook Failures:

    • Check hook commands for typos or missing dependencies (e.g., npm for asset builds).
    • Test hooks manually before integrating them.
  4. Broken Links:

    • Use browser dev tools to validate static HTML links after export.
    • Add a link-checker hook (e.g., with HTML Link Checker).

Extension Points

  1. Custom Crawlers: Extend the Spatie\Crawler\Crawler class to add logic (e.g., skip routes with X-Robots-Tag: noindex).

  2. Post-Export Processing: Use the after hook to run custom scripts (e.g., image optimization):

    'after' => [
        'optimize-images' => 'php artisan image-optimize',
    ],
    
  3. Dynamic Headers: Override the X-Laravel-Export header in middleware to conditionally include/exclude routes:

    if ($request->header('X-Laravel-Export')) {
        // Allow static export
    }
    
  4. Custom File Inclusion: Create a custom IncludeFile class to handle non-standard file types (e.g., Markdown files):

    use Spatie\Export\IncludeFile;
    
    class CustomIncludeFile extends IncludeFile
    {
        public function handle($path)
        {
            if (str_ends_with($path, '.md')) {
                return $this->convertMarkdownToHtml($path);
            }
            return parent::handle($path);
        }
    }
    

    Register it in the service provider:

    $this->app->bind(IncludeFile::class, CustomIncludeFile::class);
    

Performance Tips

  1. Exclude Unnecessary Routes: Limit paths to essential routes to reduce crawl time:

    'paths' => [
        '/',
        '/posts/{slug}',
    ],
    
  2. Parallel Exports: Use Laravel queues to run exports asynchronously for large sites:

    // In a command or job
    Export::dispatch();
    
  3. Cache Crawled URLs: Cache the list of crawled URLs to avoid re-scanning:

    $exporter->crawlCache()->rememberFor(minutes: 60);
    
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.
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
ecotone/kafka
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata