This guide covers how to deploy the Metis Admin Template to various hosting platforms.
- Building for Production
- Static Hosting
- Server Deployment
- Docker Deployment
- CI/CD Integration
- Performance Optimization
# Install dependencies (if not already done)
npm install
# Create production build
npm run buildThis generates optimized files in the dist-modern/ directory:
dist-modern/
├── assets/
│ ├── main-[hash].js # Main application bundle
│ ├── main-[hash].css # Compiled CSS
│ ├── vendor-bootstrap-[hash].js
│ ├── vendor-charts-[hash].js
│ ├── vendor-ui-[hash].js
│ └── [page]-[hash].js # Page-specific bundles
├── index.html
├── analytics.html
├── users.html
└── ... (other HTML pages)
# Preview the production build locally
npm run preview
# The preview server runs at http://localhost:4173Create environment files for different deployments:
# .env.production
VITE_API_URL=https://api.yourdomain.com
VITE_ENABLE_DEMO_DATA=false
# .env.staging
VITE_API_URL=https://staging-api.yourdomain.com
VITE_ENABLE_DEMO_DATA=trueBuild with specific environment:
# Uses .env.production
npm run build
# Uses .env.staging
npm run build -- --mode stagingOption 1: Git Integration
- Connect your repository to Netlify
- Configure build settings:
- Build command:
npm run build - Publish directory:
dist-modern
- Build command:
Option 2: Manual Deploy
# Install Netlify CLI
npm install -g netlify-cli
# Build and deploy
npm run build
netlify deploy --prod --dir=dist-modernnetlify.toml configuration:
[build]
command = "npm run build"
publish = "dist-modern"
[[redirects]]
from = "/*"
to = "/index.html"
status = 200Option 1: Git Integration
- Import project from GitHub/GitLab
- Framework preset: Vite
- Output directory:
dist-modern
Option 2: CLI Deploy
# Install Vercel CLI
npm install -g vercel
# Deploy
vercel --prodvercel.json configuration:
{
"buildCommand": "npm run build",
"outputDirectory": "dist-modern",
"framework": "vite"
}Using GitHub Actions:
Create .github/workflows/deploy.yml:
name: Deploy to GitHub Pages
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
env:
BASE_URL: /your-repo-name/
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dist-modernConfigure base URL in vite.config.js:
export default defineConfig({
base: process.env.BASE_URL || '/',
// ... other config
});1. Create S3 Bucket:
aws s3 mb s3://your-bucket-name --region us-east-12. Configure for static hosting:
{
"IndexDocument": { "Suffix": "index.html" },
"ErrorDocument": { "Key": "index.html" }
}3. Deploy:
npm run build
aws s3 sync dist-modern/ s3://your-bucket-name --delete4. Create CloudFront distribution for HTTPS and CDN caching.
# Install Firebase CLI
npm install -g firebase-tools
# Initialize
firebase init hosting
# Deploy
npm run build
firebase deployfirebase.json:
{
"hosting": {
"public": "dist-modern",
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
"rewrites": [
{ "source": "**", "destination": "/index.html" }
]
}
}server {
listen 80;
server_name yourdomain.com;
root /var/www/metis-admin/dist-modern;
index index.html;
# Gzip compression
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
gzip_min_length 1000;
# Cache static assets
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# HTML files - no cache
location ~* \.html$ {
expires -1;
add_header Cache-Control "no-store, no-cache, must-revalidate";
}
# SPA fallback
location / {
try_files $uri $uri/ /index.html;
}
}With SSL (Let's Encrypt):
server {
listen 443 ssl http2;
server_name yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
# ... rest of config
}
server {
listen 80;
server_name yourdomain.com;
return 301 https://$server_name$request_uri;
}.htaccess:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</IfModule>
# Compression
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html text/css application/javascript application/json
</IfModule>
# Caching
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType text/css "access plus 1 year"
ExpiresByType application/javascript "access plus 1 year"
ExpiresByType image/png "access plus 1 year"
ExpiresByType image/svg+xml "access plus 1 year"
</IfModule># Build stage
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Production stage
FROM nginx:alpine
COPY --from=build /app/dist-modern /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]server {
listen 80;
root /usr/share/nginx/html;
index index.html;
gzip on;
gzip_types text/plain text/css application/json application/javascript;
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
location / {
try_files $uri $uri/ /index.html;
}
}version: '3.8'
services:
metis-admin:
build: .
ports:
- "80:80"
restart: unless-stopped# Build image
docker build -t metis-admin .
# Run container
docker run -d -p 80:80 metis-admin
# Or with docker-compose
docker-compose up -dname: CI/CD
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run lint
- run: npm run build
deploy:
needs: test
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run build
- name: Deploy
run: |
# Add your deployment commands here
echo "Deploying to production..."stages:
- test
- build
- deploy
variables:
NODE_VERSION: "20"
test:
stage: test
image: node:${NODE_VERSION}
cache:
paths:
- node_modules/
script:
- npm ci
- npm run lint
build:
stage: build
image: node:${NODE_VERSION}
cache:
paths:
- node_modules/
script:
- npm ci
- npm run build
artifacts:
paths:
- dist-modern/
expire_in: 1 week
deploy:
stage: deploy
only:
- main
script:
- echo "Deploying to production..."- Run
npm run lint- no errors - Run
npm run build- successful build - Run
npm run preview- test locally - Check bundle sizes in build output
- Verify all pages load correctly
- Test dark/light mode
- Test on mobile devices
1. Analyze Bundle Size:
# Install bundle analyzer
npm install --save-dev rollup-plugin-visualizer
# Add to vite.config.js
import { visualizer } from 'rollup-plugin-visualizer';
export default defineConfig({
plugins: [
visualizer({ open: true })
]
});2. Enable Compression:
Most hosting platforms handle this automatically. For custom servers, enable gzip/brotli.
3. Use CDN for Static Assets:
Configure your hosting to serve assets from a CDN for better global performance.
4. Set Proper Cache Headers:
- HTML files:
no-cache - JS/CSS with hashes:
max-age=31536000, immutable - Images:
max-age=86400
5. Lazy Load Images:
<img src="image.jpg" loading="lazy" alt="Description">- Performance: 90+
- Accessibility: 90+
- Best Practices: 90+
- SEO: 90+
1. 404 errors on page refresh
Solution: Configure server for SPA routing (see Nginx/Apache configs above).
2. Assets not loading
Check the base option in vite.config.js matches your deployment path.
3. CORS errors
Configure your API server to allow requests from your deployment domain.
4. Build fails
# Clear cache and rebuild
rm -rf node_modules dist-modern
npm install
npm run buildFor additional help, see the GitHub Issues page.