Skip to content

feat: add proper social card image for Open Graph sharing#39

Merged
baezor merged 1 commit intodevelopfrom
feature/social-card-image
Jan 26, 2026
Merged

feat: add proper social card image for Open Graph sharing#39
baezor merged 1 commit intodevelopfrom
feature/social-card-image

Conversation

@baezor
Copy link
Owner

@baezor baezor commented Jan 26, 2026

Summary

  • Add a branded 1200x630px social card image for better social media sharing appearance
  • Replace default favicon.png (12KB) with proper social card (40KB) for og:image
  • Blog posts with hero images now use them for og:image instead of the default
  • Add @/assets/* path alias to tsconfig.json

Changes

File Change
src/assets/social-card.png New branded social card image
scripts/generate-social-card.mjs Script to regenerate social card if needed
src/components/BaseHead.astro Import default social card, handle ImageMetadata type
src/layouts/Layout.astro Add image prop passthrough
src/layouts/BlogPost.astro Pass heroImage to Layout
tsconfig.json Add @/assets/* path alias

Test plan

  • Run npm run build - passes without errors
  • Verify og:image on homepage uses social card
  • Verify og:image on blog post with heroImage uses the hero image
  • Verify og:image on blog post without heroImage uses social card
  • Test with social preview tools (Twitter Card Validator, Facebook Debugger)

Replace default favicon.png (12KB) with a branded 1200x630 social card
image for better appearance when sharing on social media. Blog posts
with hero images now use them for og:image, while other pages use the
default social card.
@cloudflare-workers-and-pages
Copy link

Deploying baezor with  Cloudflare Pages  Cloudflare Pages

Latest commit: ec2ef0d
Status: ✅  Deploy successful!
Preview URL: https://49099f6b.baezor.pages.dev
Branch Preview URL: https://feature-social-card-image.baezor.pages.dev

View logs

@claude
Copy link

claude bot commented Jan 26, 2026

Code Review - PR #39

Summary

This PR adds a proper social card image for Open Graph sharing. The implementation improves social media sharing appearance by replacing the default favicon with a branded 1200x630px social card and enabling blog posts to use their hero images for social sharing.


✅ Strengths

  1. Good architecture - Proper use of path aliases and Astro's image handling
  2. Type safety - Correctly handles both string and ImageMetadata types
  3. Follows conventions - Adheres to the project's GitFlow and commit message standards
  4. Smart fallback - Blog posts with hero images use them, others fall back to the default social card

🐛 Critical Issues

1. Missing Dependency: sharp

Severity: High 🔴

The scripts/generate-social-card.mjs script imports sharp but it's not listed in package.json dependencies.

Location: scripts/generate-social-card.mjs:1

import sharp from 'sharp';

Impact:

  • The script will fail when someone tries to regenerate the social card
  • New contributors won't be able to run the generation script

Fix:

npm install --save-dev sharp

2. Variable Naming Collision Risk

Severity: Medium 🟡

In BaseHead.astro, the variable imageUrl is used both as a local variable and then redefined in the structured data script.

Location: src/components/BaseHead.astro:27-29, src/components/BaseHead.astro:93

Current code:

const imageUrl = typeof image === 'string'
  ? new URL(image, SITE_URL)
  : new URL(image.src, SITE_URL);
// ...later...
<script is:inline define:vars={{ siteUrl: SITE_URL, schemaImageUrl: imageUrl.toString() }} type="application/ld+json">

Good news: This was actually fixed! The variable was renamed to schemaImageUrl in the structured data to avoid collision. However, the fix is inconsistent - the define:vars creates a new schemaImageUrl variable, but then uses it as image in the JSON-LD.

Recommendation: Verify that the structured data is correctly receiving the image URL.


⚠️ Security Concerns

3. Google Fonts External Request in SVG

Severity: Low 🟡

The SVG template loads Google Fonts via an external @import which could pose issues:

Location: scripts/generate-social-card.mjs:21

@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@600;700&display=swap');

Issues:

  • Network dependency: Requires internet connection to generate the card
  • Privacy: External request during build (though this is offline generation, not runtime)
  • Reliability: If Google Fonts is down, generation fails

Recommendation: Consider using a locally installed font or embedding the font data in the SVG. However, this may be acceptable for a script that's run manually.


🧪 Test Coverage Issues

4. No Tests for Image Handling Logic

Severity: Medium 🟡

The new image type handling logic in BaseHead.astro is untested.

Location: src/components/BaseHead.astro:27-29

Missing tests:

  • Unit test for string image path handling
  • Unit test for ImageMetadata object handling
  • Visual regression test for og:image meta tag content

Recommendation: Add a unit test to verify the image URL logic:

// tests/components/BaseHead.test.ts
describe('BaseHead image handling', () => {
  it('should handle string image paths', () => {
    // Test that string paths are converted to URLs correctly
  });
  
  it('should handle ImageMetadata objects', () => {
    // Test that ImageMetadata.src is used correctly
  });
});

5. Visual Regression Tests Need Verification

Severity: Low 🟡

According to the test plan, visual verification is incomplete. The PR changes how og:image is rendered but visual regression tests may not catch this since they test visible UI, not meta tags.

Recommendation: Consider adding a specific test to verify meta tags:

// tests/visual/og-tags.spec.ts
test('homepage has correct og:image', async ({ page }) => {
  await page.goto('/');
  const ogImage = await page.locator('meta[property="og:image"]').getAttribute('content');
  expect(ogImage).toContain('social-card');
});

test('blog post with hero image uses hero for og:image', async ({ page }) => {
  await page.goto('/blog/visual-regression-testing-with-playwright');
  const ogImage = await page.locator('meta[property="og:image"]').getAttribute('content');
  // Verify it's not the default social card
  expect(ogImage).not.toContain('social-card');
});

📝 Code Quality Suggestions

6. Script Documentation

Severity: Low 🟢

The generate-social-card.mjs script lacks usage documentation.

Recommendation: Add a header comment:

/**
 * Generates a branded social card image for Open Graph sharing.
 * 
 * Usage:
 *   node scripts/generate-social-card.mjs
 * 
 * Requirements:
 *   - sharp must be installed (npm install -D sharp)
 * 
 * Output:
 *   - src/assets/social-card.png (1200x630px)
 */

7. TypeScript Type Import

Severity: Low 🟢

Good practice: Using type imports for types helps with tree-shaking and makes it clear what's a type.

Current:

import type { ImageMetadata } from "astro";

This is perfect! ✅ No changes needed.


🎯 Performance Considerations

8. Image Size is Acceptable

The new social card (40KB) is larger than the old favicon (12KB), but:

  • ✅ It's only loaded for social media crawlers, not users
  • ✅ 40KB is reasonable for a 1200x630 image
  • ✅ The increase is worth the improved social sharing appearance

No action needed


📋 Checklist Before Merge

  • Add sharp to devDependencies
  • Verify structured data correctly receives the image URL (test with validator)
  • Consider adding unit tests for image handling logic
  • Consider adding meta tag verification tests
  • Complete the test plan items in the PR description:
    • Verify og:image on homepage uses social card
    • Verify og:image on blog post with heroImage uses the hero image
    • Verify og:image on blog post without heroImage uses social card
    • Test with social preview tools (Twitter Card Validator, Facebook Debugger)
  • Update snapshots if visual regression tests fail (run npm run test:visual:update)
  • Ensure npm run build passes
  • Ensure all CI checks pass

🎉 Overall Assessment

Verdict: Approve with required changes⚠️

This is a solid implementation that improves the social sharing experience. The main blocker is the missing sharp dependency. Once that's addressed, this PR will be ready to merge.

Estimated Impact:

  • User Experience: High positive - much better social sharing appearance
  • Code Quality: Good - follows project conventions
  • Risk: Low - isolated changes with good fallback behavior

💡 Nice to Have (Future Enhancements)

  1. Consider adding dynamic social card generation for blog posts (using the script with post-specific content)
  2. Add OG image dimensions meta tags (og:image:width and og:image:height)
  3. Document the social card generation process in README or contributing guide

Great work overall! The implementation is clean and well-structured. Just address the missing dependency and verify the test plan, and this will be good to go. 🚀

@baezor baezor merged commit d67d558 into develop Jan 26, 2026
2 checks passed
@baezor baezor mentioned this pull request Jan 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant