Web build deploy
Skill aiskillstore/marketplace/skills/cjharmath/web-build-deploy
Security-audited skills for Claude, Codex & Claude Code. One-click install, quality verified.
npx -y skills add aiskillstore/marketplace --skill web-build-deployAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
What its author says it does
Copied from the file, not written here
Building and deploying React web applications. Use when configuring builds, deploying to Vercel/Netlify, setting up CI/CD, Docker, or managing environments.
SKILL.md
8.4 KB, as published. Nobody here has run it
Web Build & Deploy (React)
Vercel Deployment
Quick Deploy
# Install Vercel CLI
npm i -g vercel
# Deploy
vercel
# Deploy to production
vercel --prod
Configuration (vercel.json)
{
"buildCommand": "npm run build",
"outputDirectory": "dist",
"framework": "vite",
"rewrites": [
{ "source": "/(.*)", "destination": "/" }
],
"headers": [
{
"source": "/(.*)",
"headers": [
{ "key": "X-Content-Type-Options", "value": "nosniff" },
{ "key": "X-Frame-Options", "value": "DENY" }
]
}
]
}
Environment Variables
# Add via CLI
vercel env add NEXT_PUBLIC_API_URL
# Or in Vercel dashboard: Settings > Environment Variables
# Access in code
const apiUrl = process.env.NEXT_PUBLIC_API_URL;
Preview Deployments
Every push to a branch creates a preview URL automatically:
https://project-git-branch-username.vercel.app
Netlify Deployment
Quick Deploy
# Install Netlify CLI
npm i -g netlify-cli
# Login
netlify login
# Deploy preview
netlify deploy
# Deploy to production
netlify deploy --prod
Configuration (netlify.toml)
[build]
command = "npm run build"
publish = "dist"
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
[[headers]]
for = "/*"
[headers.values]
X-Frame-Options = "DENY"
X-Content-Type-Options = "nosniff"
[build.environment]
NODE_VERSION = "18"
Environment Variables
# Add via CLI
netlify env:set API_URL https://api.example.com
# Or in Netlify dashboard: Site settings > Environment variables
Docker Deployment
Dockerfile (Multi-stage build)
# Build stage
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Production stage
FROM nginx:alpine
# Copy built files
COPY --from=builder /app/dist /usr/share/nginx/html
# Copy nginx config for SPA routing
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
nginx.conf (SPA routing)
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
# Gzip compression
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
# Cache static assets
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# SPA fallback
location / {
try_files $uri $uri/ /index.html;
}
# Security headers
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
}
Docker Compose
# docker-compose.yml
version: '3.8'
services:
web:
build: .
ports:
- "80:80"
environment:
- NODE_ENV=production
restart: unless-stopped
# With backend
api:
build: ./backend
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgresql://user:pass@db:5432/app
depends_on:
- db
db:
image: postgres:15-alpine
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
- POSTGRES_USER=user
- POSTGRES_PASSWORD=pass
- POSTGRES_DB=app
volumes:
postgres_data:
Build & Run
# Build image
docker build -t myapp:latest .
# Run container
docker run -p 80:80 myapp:latest
# With docker-compose
docker-compose up -d
docker-compose down
GitHub Actions CI/CD
Basic Workflow
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Build
run: npm run build
env:
VITE_API_URL: ${{ secrets.API_URL }}
- name: Deploy to Vercel
if: github.ref == 'refs/heads/main'
uses: amondnet/vercel-action@v25
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
vercel-args: '--prod'
With Preview Deployments
name: Preview
on: [pull_request]
jobs:
preview:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy Preview
uses: amondnet/vercel-action@v25
id: deploy
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
- name: Comment PR
uses: actions/github-script@v6
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '🚀 Preview deployed to: ${{ steps.deploy.outputs.preview-url }}'
})
Environment Configuration
Vite
// vite.config.ts
import { defineConfig, loadEnv } from 'vite';
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd(), '');
return {
define: {
'process.env.API_URL': JSON.stringify(env.VITE_API_URL),
},
};
});
# .env.development
VITE_API_URL=http://localhost:8000
# .env.production
VITE_API_URL=https://api.example.com
Next.js
# .env.local (not committed)
DATABASE_URL=postgresql://localhost:5432/dev
# .env.production
NEXT_PUBLIC_API_URL=https://api.example.com
// Access in code
// Client-side (must start with NEXT_PUBLIC_)
const apiUrl = process.env.NEXT_PUBLIC_API_URL;
// Server-side only
const dbUrl = process.env.DATABASE_URL;
Build Optimization
Vite Build Analysis
# Install analyzer
npm i -D rollup-plugin-visualizer
# Add to vite.config.ts
import { visualizer } from 'rollup-plugin-visualizer';
export default defineConfig({
plugins: [
visualizer({
filename: 'stats.html',
open: true,
}),
],
});
# Build and analyze
npm run build
Code Splitting
// Route-based splitting
const Dashboard = lazy(() => import('./pages/Dashboard'));
const Settings = lazy(() => import('./pages/Settings'));
// Component splitting
const HeavyChart = lazy(() => import('./components/HeavyChart'));
Caching Strategy
// vite.config.ts
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks: {
vendor: ['react', 'react-dom'],
router: ['react-router-dom'],
ui: ['@radix-ui/react-dialog', '@radix-ui/react-dropdown-menu'],
},
},
},
},
});
Health Checks & Monitoring
Health Check Endpoint
// For Docker/Kubernetes
// api/health.ts (Next.js)
export async function GET() {
return Response.json({ status: 'healthy', timestamp: Date.now() });
}
Error Tracking (Sentry)
// sentry.client.config.ts
import * as Sentry from '@sentry/react';
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
environment: process.env.NODE_ENV,
tracesSampleRate: 0.1,
});
// Wrap app
const SentryRoutes = Sentry.withSentryReactRouterV6Routing(Routes);
Common Issues
| Issue | Solution |
|---|---|
| 404 on refresh (SPA) | Configure server for SPA fallback |
| Environment vars undefined | Check prefix (VITE_, NEXT_PUBLIC_) |
| Build fails on CI | Check Node version, clear cache |
| Docker image too large | Use multi-stage build, alpine base |
| Slow builds | Enable caching, parallelize |
Deployment Checklist
Before deploying to production:
- Environment variables set
- Build succeeds locally
- Tests pass
- Security headers configured
- Error tracking enabled
- Performance optimized (bundle size, code splitting)
- SEO meta tags (if applicable)
- SSL/HTTPS enabled
- Custom domain configured
- Health check endpoint working