How I Rebuilt Shaan Puri's Blog with Laravel & Cloudflare to Get Perfect 100 Google Web Vitals Scores

Play YouTube Video

Join me as I rebuild Shaan Puri's blog using Laravel, Nuxt, and Cloudflare, achieving perfect 100 Google Core Web Vitals scores. This post guides you through the entire process, highlighting key optimizations for web performance.

Table of Contents

Featured Technologies

  • Laravel
  • Nuxt
  • Cloudflare D1
  • Cloudflare Pages
  • Cloudflare Workers
  • Cloudflare KV store
  • TailwindCSS
  • Vue.js
  • REST API

Important Links

Steps for Rebuilding Shaan Puri's Blog

Create the Nuxt App and Deploy to Cloudflare Pages

  1. Make sure you create a Cloudflare account.
  2. Log in to your Cloudflare account.
  3. In your terminal run: npx wrangler login
  4. Run: pnpm create cloudflare@latest blog-app-client
  5. Select Website or web app.
  6. Select Nuxt.
  7. When asked "Do you want to deploy your application?" select yes.
  8. Change into the newly created directory with cd blog-app-client.
  9. You can run the template app with pnpm run dev.
  10. And you can deploy any new changes to the app with pnpm run deploy.
  11. Initialize git in the directory with git init.
  12. Create a new repository in GitHub and then connect and push your local app to the newly created repository.
  13. Add TailwindCSS to your app:
    • Run npx nuxi@latest module add tailwindcss
    • Create your TailwindCSS config file with npx tailwindcss init --ts
  14. Push your latest changes to git with git commit -m "add tailwind to nuxt app".
  15. Now you can style and build your Nuxt app as you choose.

Create a SQLite Database using Cloudflare's D1 Database

  1. Run npx wrangler d1 create blog-db.
  2. Save the database_id found in the terminal for later use in your Laravel web server.

Create the Laravel Web Server

  1. Ensure you have PHP and Composer installed and running on your local machine.
  2. Create a default Laravel app:
    • In a new directory run composer create-project --prefer-dist laravel/laravel="10.*" laravel-api && cd laravel-api.
  3. In the directory of your Laravel web server, open the .env file and add the following environment variables:
    • CLOUDFLARE_D1_DATABASE_ID
    • CLOUDFLARE_ACCOUNT_ID
    • CLOUDFLARE_TOKEN
  4. Create the D1 database connection with the L1 library:
    • Run composer require renoki-co/l1.
    • In config/database.php add the following connector:
      
              
        'connections' => [
          'd1' => [
            'driver' => 'd1',
            'prefix' => '',
            'database' => env('CLOUDFLARE_D1_DATABASE_ID', ''),
            'api' => 'https://api.cloudflare.com/client/v4',
            'auth' => [
              'token' => env('CLOUDFLARE_TOKEN', ''),
              'account_id' => env('CLOUDFLARE_ACCOUNT_ID', ''),
            ],
          ],
        ],
      
              
    • Set the Default Database Connection Name to 'd1':
      
      'default' => 'd1',
      
              

Create the Model, Controllers, and API Routes

  1. Think about the data you want to persist in the D1 database.
  2. Create your first model in the laravel-api directory:
    • Run php artisan make:model articles -m.
  3. Update the up function in the newly created migration file in database/migrations/ to match your schema:
  4. 
    use IlluminateDatabaseMigrationsMigration;
    use IlluminateDatabaseSchemaBlueprint;
    use IlluminateSupportFacadesSchema;
    
    return new class extends Migration
    {
      /**
       * Run the migrations.
       */
      public function up(): void
      {
        Schema::create('articles', function (Blueprint $table) {
          $table->id();
          $table->timestamps();
          $table->string('slug')->unique();
          $table->string('title');
          $table->text('description')->nullable();
          $table->longText('body');
          $table->string('author_full_name')->nullable();
          $table->string('cover_img_src')->nullable();
          $table->string('cover_img_alt')->nullable();
          $table->boolean('is_active')->default(true);
          $table->date('published_date');
          $table->string('read_time');
          $table->index(['slug', 'is_active']);
        });
      }
    
      /**
       * Reverse the migrations.
       */
      public function down(): void
      {
        Schema::dropIfExists('articles');
      }
    };  
        
        
  5. Run your first migration against the D1 database:
    • Run php artisan migrate.
  6. Check your migration in the Cloudflare dashboard.
  7. Update the model file in app/Models/ to define which attributes are assignable:
    
          
    namespace AppModels;
    
    use IlluminateDatabaseEloquentFactoriesHasFactory;
    use IlluminateDatabaseEloquentModel;
    
    class articles extends Model
    {
    use HasFactory;
    
    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
      'slug', 'title', 'description', 'body', 'author_full_name', 'cover_img_src', 'cover_img_alt', 'is_active', 'published_date', 'read_time',
    ];
    }
          
          
  8. Create the controller:
    • Run php artisan make:controller ArticleController.
  9. Add public methods for each CRUD action in the controller file.
  10. Define the API endpoints for your Laravel REST API in routes/api.php.
  11. Test your Laravel API server:
    • Run php artisan serve.

Create a Cloudflare Worker for the Cache Layer

  1. Back out of your Laravel API directory and prepare to create your Cloudflare Worker:
    • Run pnpm create cloudflare@latest blog-worker.
  2. Follow the prompts in the terminal:
    • Select Hello World Worker.
    • Select Yes for TypeScript.
    • Select Yes to deploy your application.
  3. Change directory into your new Cloudflare Worker:
    • Run pnpm run start.
    • Run pnpm run deploy.
  4. Use this worker as a cache layer to reduce latency for visitors to the blog.

Conclusion

By following these steps, you can achieve perfect 100 Google Web Vitals scores for your blog. Leveraging Laravel, Nuxt, and Cloudflare, you can create a fast, efficient, and scalable blog that provides an excellent user experience.

Stay Updated