Appearance
๐ CDN Integration Guide (AWS S3 + CloudFront + Vite + Vercel) โ
Goal: Serve static assets (images, CSS, JS, fonts, etc.) efficiently from AWS S3 + CloudFront while deploying your Vue 3 + Vite app via Vercel.
This setup ensures blazing-fast asset delivery, cache safety, easy rollbacks, and lightweight frontend deployments.
๐งฉ Project Overview โ
This setup supports three distinct build modes:
| Build Type | Description | Use Case |
|---|---|---|
Local Build (npm run build) | Normal Vite build, serves assets locally from /assets/. | Local development. |
Timestamped Build (npm run build:ts) | Builds and uploads versioned assets (e.g., /assets/20251004175023/assets/). | Local testing of CDN flow. |
| Production Build (via GitHub Actions) | Builds timestamped assets, uploads to S3 + CloudFront, and deploys the app to Vercel. | CI/CD deployment for production. |
โ๏ธ 1. Local Build Flow (npm run dev or npm run build) โ
๐น Purpose โ
For quick development and testing using your local server.
๐น Flow โ
- The
getAssets.jsfile dynamically imports all images (and subdirectories) from/src/assets/. - The Vue app uses Vueโs
provide/injectAPI to make these images globally accessible.
Example:
js
// getAssets.js
const modules = import.meta.glob('./**/*.@(jpg|png|gif|svg)', { eager: true });
let images = {};
for (const path in modules) {
const fileName = path.split('/').pop();
images[fileName] = modules[path].default;
}
export default images;App setup:
js
// main.js
import { createApp } from 'vue';
import App from './App.vue';
import images from './assets/getAssets.js';
const app = createApp(App);
app.provide('appImages', images);
app.mount('#app');In components:
vue
<img :src="appImages['logo.png']" alt="Logo" />โ
Assets are resolved from local /assets/ folder. โ No CDN or AWS involvement.
๐ 2. Timestamped Build Flow (npm run build:ts) โ
๐น Purpose โ
To test the CDN flow locally, ensuring that assets are built, uploaded to S3, and linked correctly in the HTML.
๐น Key Behavior โ
Generates a timestamp like
20251004175023Builds your app using Vite with that timestamp
Uploads the built assets to:
s3://test-cdn-pipeline/assets/<timestamp>/assets/Rewrites asset URLs in
index.html:https://d2ip2t1fu9lfn9.cloudfront.net/assets/<timestamp>/assets/<file>.js
๐น Environment Requirements โ
You need a .env.production file locally:
env
AWS_ACCESS_KEY_ID=your-access-key
AWS_SECRET_ACCESS_KEY=your-secret-key
VITE_CDN_URL=https://<your-cloudfront-domain>๐น Commands โ
bash
npm run build:ts๐น Under the Hood โ
build:ts triggers scripts/build-and-upload.js, which:
- Generates a timestamp.
- Runs
vite buildwith that timestamp. - Uploads the
dist/assetsfolder to S3 under/assets/<timestamp>/assets/.
๐ 3. Production Build Flow (CI/CD) โ
Triggered automatically on push to main branch via GitHub Actions.
๐น Pipeline Overview โ
build.ymlโ Builds app and setsBUILD_TIMESTAMP.upload-assets.ymlโ Uploads assets to:/assets/<timestamp>/assets/(versioned)/assets/latest/(for production)- Invalidates CloudFront cache.
deploy-vercel.ymlโ Deploys the latestdistfolder to Vercel.
๐น GitHub Secrets Required โ
| Secret Name | Description |
|---|---|
AWS_ACCESS_KEY_ID | IAM access key with S3 + CloudFront permissions. |
AWS_SECRET_ACCESS_KEY | Secret key for the above. |
AWS_REGION | Your AWS region (e.g., eu-north-1). |
CLOUDFRONT_DIST_ID | Your CloudFront distribution ID. |
VERCEL_TOKEN | Vercel personal access token. |
VERCEL_PROJECT_ID | Vercel project ID. |
VERCEL_ORG_ID | Vercel organization ID. |
VITE_CDN_URL | CloudFront URL (e.g., https://dxxxxx.cloudfront.net). |
๐ง 4. AWS Setup Guide โ
๐ชณ S3 Bucket Setup โ
- Create an S3 bucket (e.g.,
test-cdn-pipeline). - Disable โBlock all public access.โ
- Enable versioning if you want historical rollbacks.
- Add this bucket policy (replace with your CloudFront distribution ID):
json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCloudFrontServicePrincipal",
"Effect": "Allow",
"Principal": { "Service": "cloudfront.amazonaws.com" },
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::test-cdn-pipeline/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::<YOUR_AWS_ACCOUNT_ID>:distribution/<YOUR_DIST_ID>"
}
}
}
]
}๐ CloudFront Setup โ
Origin Domain: your S3 bucket (e.g.,
test-cdn-pipeline.s3.eu-north-1.amazonaws.com)Origin Access Control (OAC):
- Create a new OAC and attach it to your S3 bucket.
Viewer Protocol Policy: Redirect HTTP โ HTTPS
Cache Policy:
Managed-CachingOptimizedOrigin Request Policy:
Managed-CORS-With-PreflightResponse Header Policy: none (optional)
โณ Lifecycle Rules โ
In your S3 bucket โ Management โ Lifecycle Rules, add:
- Rule name: delete-old-asset-versions
- Prefix:
assets/ - Action: Delete objects older than
1 day - Filter: Include all objects
- Enabled: โ Yes
This keeps the bucket clean by auto-deleting old timestamped folders, leaving only recent ones.
๐ File Reference Overview โ
| File | Purpose |
|---|---|
vite.config.js | Handles asset URL rewriting to CDN. |
scripts/deploy-cdn.js | Uploads built files to S3 and rewrites HTML. |
scripts/build-and-upload.js | Generates timestamp, builds app, and calls deploy script. |
.github/workflows/build.yml | Automates full CI/CD build, upload, and deploy. |
.github/workflows/upload-assets.yml | Uploads assets and invalidates cache. |
.github/workflows/deploy-vercel.yml | Deploys built app to Vercel. |
๐ง Rollback Strategy โ
Each build is stored under /assets/<timestamp>/assets/. To roll back:
Find your previous timestamp folder in S3.
Replace
latestwith that version manually:bashaws s3 sync s3://test-cdn-pipeline/assets/20251004175023/assets/ s3://test-cdn-pipeline/assets/latest/assets/ --deleteInvalidate CloudFront cache.
๐ณ Summary โ
| Feature | Local | Timestamp | Production |
|---|---|---|---|
| Assets Location | /assets/ | /assets/<timestamp>/assets/ | /assets/latest/ |
| CDN Used | โ | โ | โ |
| Upload to S3 | โ | โ | โ |
| CloudFront Invalidation | โ | โ | โ |
| Auto Cleanup | โ | โ via Lifecycle | โ via Lifecycle |
| Deployment | Local | Local Test | Vercel CI/CD |
๐งช Pro Tips โ
Use timestamped builds for internal QA / preview environments.
Always keep the latest folder synced for production.
If a file gets 403 (Access Denied), double-check:
- S3 policy matches CloudFront OAC ARN.
- CloudFront cache is invalidated.
- The bucket region and distribution are correctly configured.
โค๏ธ Credits โ
Created for a scalable Vite + Vue + AWS + Vercel CDN pipeline by Altersquare