Thêm ảnh vào Astro trên Cloudflare Pages
Thêm ảnh vào Astro trên Cloudflare Pages
Section titled “Thêm ảnh vào Astro trên Cloudflare Pages”Cloudflare Pages là hosting miễn phí tuyệt vờI cho Astro sites. Bài viết này hướng dẫn cách quản lý và sử dụng hình ảnh trên Cloudflare Pages.
1. Các phương án lưu trữ ảnh
Section titled “1. Các phương án lưu trữ ảnh”So sánh các options
Section titled “So sánh các options”| Phương án | Giá | Tốt cho | Hạn chế |
|---|---|---|---|
| public/ | Free | < 100 ảnh, < 20MB | Build chậm hơn |
| Cloudflare Images | $5/100k images | Dynamic resize | Paid |
| R2 Storage | $0.015/GB | Bulk storage | Setup phức tạp |
| External CDN | Free/Paid | Existing workflow | Dependency |
2. Phương án 1: public/ folder (Recommended cho beginners)
Section titled “2. Phương án 1: public/ folder (Recommended cho beginners)”Cấu trúc thư mục
Section titled “Cấu trúc thư mục”my-astro-blog/├── public/│ └── images/│ ├── posts/│ │ ├── 2024/│ │ │ └── bai-viet-1/│ │ │ ├── hero.jpg│ │ │ └── diagram.png│ │ └── 2023/│ ├── authors/│ │ ├── avatar-john.jpg│ │ └── avatar-jane.jpg│ └── shared/│ └── logo.png└── src/ └── content/ └── blog/Sử dụng trong Markdown
Section titled “Sử dụng trong Markdown”
<!-- Hoặc với size cụ thể --><img src="/images/posts/2024/bai-viet-1/hero.jpg" alt="Description" width="800" height="450"/>Sử dụng trong Astro
Section titled “Sử dụng trong Astro”---import { Image } from 'astro:assets';---
<!-- Local image --><Image src="/images/posts/2024/bai-viet-1/hero.jpg" alt="Description" width={800} height={450} format="webp"/>
<!-- Hoặc dynamic --><img src={`/images/posts/${post.slug}/hero.jpg`} alt={post.data.title}/>Git LFS cho large files
Section titled “Git LFS cho large files”Nếu repo lớn, dùng Git LFS:
# Install Git LFSgit lfs install
# Track imagesgit lfs track "*.jpg"git lfs track "*.png"git lfs track "*.webp"
# Commitgit add .gitattributesgit add public/images/git commit -m "Add images with LFS"3. Phương án 2: Cloudflare Images (Best cho dynamic resize)
Section titled “3. Phương án 2: Cloudflare Images (Best cho dynamic resize)”Setup Cloudflare Images
Section titled “Setup Cloudflare Images”-
Trong Cloudflare Dashboard:
- Vào Images → Configuration
- Enable “Cloudflare Images”
- Copy Delivery URL
-
Upload images:
# Via APIcurl -X POST \ https://api.cloudflare.com/client/v4/accounts/YOUR_ACCOUNT/images/v1 \ -H "Authorization: Bearer YOUR_TOKEN" \ -F file=@/path/to/image.jpg- Sử dụng trong Astro:
---const imageId = 'image-id-from-upload';const accountHash = 'your-account-hash';---
<!-- Direct URL --><img src={`https://imagedelivery.net/${accountHash}/${imageId}/public`} alt="Description" loading="lazy"/>
<!-- With transformations --><img src={`https://imagedelivery.net/${accountHash}/${imageId}/w=800,quality=85`} srcset={` https://imagedelivery.net/${accountHash}/${imageId}/w=400 400w, https://imagedelivery.net/${accountHash}/${imageId}/w=800 800w, https://imagedelivery.net/${accountHash}/${imageId}/w=1200 1200w `} sizes="(max-width: 600px) 400px, 800px" alt="Description"/>Transformations available
Section titled “Transformations available”| Parameter | Example | Description |
|---|---|---|
w | w=800 | Width |
h | h=600 | Height |
quality | quality=85 | Quality (1-100) |
format | format=webp | Output format |
fit | fit=cover | Resize fit |
Helper function
Section titled “Helper function”export function getCloudflareImageUrl(imageId, options = {}) { const accountHash = import.meta.env.CLOUDFLARE_ACCOUNT_HASH; const { width, quality = 85, format = 'webp' } = options;
let transform = ''; if (width) transform += `w=${width},`; transform += `quality=${quality}`; if (format) transform += `,format=${format}`;
return `https://imagedelivery.net/${accountHash}/${imageId}/${transform}`;}
// Usageimport { getCloudflareImageUrl } from '../utils/images.js';
const imageUrl = getCloudflareImageUrl('image-id', { width: 800, quality: 85});4. Phương án 3: R2 Object Storage
Section titled “4. Phương án 3: R2 Object Storage”Setup R2 Bucket
Section titled “Setup R2 Bucket”-
Tạo R2 bucket:
- Cloudflare Dashboard → R2
- Create bucket:
my-blog-images - Set public access
-
Upload images:
# Using Wranglerwrangler r2 object put my-blog-images/posts/hero.jpg --file=./hero.jpg
# Hoặc via S3-compatible APIaws s3 cp ./images s3://my-blog-images/posts/ --recursive \ --endpoint-url https://ACCOUNT_ID.r2.cloudflarestorage.com- Custom domain cho R2:
Cloudflare Dashboard → R2 → Manage Bucket → Settings → Public Custom Hostname→ Add: images.yoursite.com- Sử dụng trong Astro:
---const R2_PUBLIC_URL = 'https://images.yoursite.com';---
<img src={`${R2_PUBLIC_URL}/posts/hero.jpg`} alt="Description" loading="lazy"/>5. Content Collection với Images
Section titled “5. Content Collection với Images”Schema cho blog posts
Section titled “Schema cho blog posts”import { defineCollection, z } from 'astro:content';
const blogCollection = defineCollection({ type: 'content', schema: z.object({ title: z.string(), date: z.date(), image: z.object({ src: z.string(), alt: z.string(), credit: z.string().optional(), }).optional(), ogImage: z.string().optional(), }),});
export const collections = { 'blog': blogCollection,};Frontmatter mẫu
Section titled “Frontmatter mẫu”---title: "Bài viết với ảnh"date: 2024-01-15image: src: "/images/posts/2024/bai-viet/hero.jpg" alt: "Mô tả ảnh hero" credit: "Photo by John Doe"ogImage: "/images/posts/2024/bai-viet/og-image.jpg"---
Nội dung bài viết...Render trong template
Section titled “Render trong template”---import { Image } from 'astro:assets';import type { CollectionEntry } from 'astro:content';
interface Props { post: CollectionEntry<'blog'>;}
const { post } = Astro.props;const { Content } = await post.render();---
<article> {post.data.image && ( <figure> <Image src={post.data.image.src} alt={post.data.image.alt} width={1200} height={630} format="webp" /> {post.data.image.credit && ( <figcaption>{post.data.image.credit}</figcaption> )} </figure> )}
<Content /></article>6. GitHub Actions cho Image Optimization
Section titled “6. GitHub Actions cho Image Optimization”Workflow tự động optimize
Section titled “Workflow tự động optimize”name: Optimize Images
on: push: paths: - 'public/images/**'
jobs: optimize: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3
- name: Setup Node uses: actions/setup-node@v3 with: node-version: 18
- name: Install dependencies run: npm install sharp
- name: Optimize images run: node scripts/optimize-images.js
- name: Commit changes run: | git config --local user.email "action@github.com" git config --local user.name "GitHub Action" git add public/images/ git diff --quiet && git diff --staged --quiet || git commit -m "Optimize images" git push7. Best Practices
Section titled “7. Best Practices”Performance tips
Section titled “Performance tips”<!-- Preload critical hero image --><link rel="preload" as="image" href="/images/hero.webp" type="image/webp"/>
<!-- Responsive images --><Image src={heroImage} alt="Hero" widths={[400, 800, 1200]} sizes="100vw" format="webp" loading="eager" fetchpriority="high"/>8. Troubleshooting
Section titled “8. Troubleshooting”| Vấn đề | Nguyên nhân | Fix |
|---|---|---|
| Images 404 | Wrong path | Kiểm tra /images/ vs images/ |
| Build chậm | Quá nhiều ảnh | Dùng Cloudflare Images hoặc R2 |
| CORS error | External images | Add CORS headers hoặc proxy |
| CLS cao | Thiếu dimensions | Thêm width/height |
Summary
Section titled “Summary”| Use Case | Recommendation |
|---|---|
| Personal blog | public/images/ |
| Photo gallery | Cloudflare Images |
| Large media site | R2 + Custom domain |
| Mixed approach | public cho static, Images cho dynamic |