Performance Optimization and Build Deployment
1. Course Introduction
(1) Prerequisites
- Bootstrap Dark Mode and Theme Switching (Lesson 21)
- Basic concepts of frontend performance metrics
- HTML and CSS resource loading mechanisms
(2) 🎯 What You Will Learn
- Analyze the resource size and loading performance of a Bootstrap project
- Use PurgeCSS to remove unused CSS
- Optimize JavaScript on-demand loading and lazy loading
- Master image optimization and CDN deployment best practices
- Configure a complete production build and deployment workflow
(3) Pain Point
Alice completed her Bootstrap portfolio website, but page loading takes 3 seconds—users might leave before the page even finishes loading. The Lighthouse score is also low.
(4) Solution
Building a page is just the first step; making it load fast and provide a great experience is the ultimate goal. This lesson compiles the best practices for performance optimization and build deployment in Bootstrap projects: CSS compression, JS on-demand loading, image optimization, CDN pre-warming—reducing load time to 0.8 seconds through optimization.
Understanding: Performance optimization = "Losing weight" for your website—removing unnecessary code, compressing resources, letting the browser cache results, so the page loads within 1 second.
(5) Benefits
Alice's Bootstrap portfolio website was optimized from 3 seconds to 0.8 seconds, significantly improving the Lighthouse score, greatly enhancing the user experience, and consequently increasing the website's conversion rate.
2. Bootstrap Size Analysis
| Resource | Uncompressed | Gzip Compressed | Notes |
|---|---|---|---|
bootstrap.min.css |
~250KB | ~28KB | Full framework |
bootstrap.bundle.min.js |
~205KB | ~22KB | Includes Popper |
bootstrap.min.js |
~170KB | ~19KB | Excludes Popper |
| Bootstrap Icons CSS | ~220KB | ~25KB | 2000+ icons |
Key Conclusion: Full Bootstrap's CSS + JS compressed is about 50KB, which is small for modern networks. The real performance impacts are images, fonts, and third-party scripts.
▶ Example: Before vs After Optimization
graph LR
subgraph "Before optimization (3s)"
A1[HTML] --> B1[Full Bootstrap CSS]
B1 --> C1[Full Bootstrap JS]
C1 --> D1[Unoptimized images]
D1 --> E1[Google Fonts CSS]
E1 --> F1[3s load time]
end
subgraph "After optimization (0.8s)"
A2[HTML] --> B2[Purged CSS ~30KB]
B2 --> C2[Lazy loaded images]
C2 --> D2[Deferred JS]
D2 --> E2[CDN cache warm]
E2 --> F2[0.8s load time]
end
Output: Bootstrap 5.3 styled components (e.g., buttons, cards, carousels, collapses), using the default Bootstrap theme (light) and responsive grid.
3. CSS Optimization
(1) On-Demand Compilation (Sass)
// Import only the modules used
@import "bootstrap/scss/functions";
@import "bootstrap/scss/variables";
@import "bootstrap/scss/mixins";
@import "bootstrap/scss/root";
@import "bootstrap/scss/reboot";
@import "bootstrap/scss/type";
@import "bootstrap/scss/grid";
@import "bootstrap/scss/buttons";
@import "bootstrap/scss/card";
@import "bootstrap/scss/navbar";
@import "bootstrap/scss/forms";
@import "bootstrap/scss/utilities";
@import "bootstrap/scss/utilities/api";
Output: Bootstrap 5.3 styled components (e.g., buttons, cards, carousels, collapses), using the default Bootstrap theme (light) and responsive grid.
(2) PurgeCSS for Redundancy Removal
PurgeCSS can analyze classes actually used in HTML/JS and delete unused CSS:
npm install -D purgecss
// purgecss.config.js
module.exports = {
content: ['.//*.html', './/*.js'],
css: ['./dist/style.css'],
safelist: ['show', 'active', 'fade', 'collapse', 'modal-open']
}
Output: Bootstrap 5.3 styled components (e.g., buttons, cards, carousels, collapses), using the default Bootstrap theme (light) and responsive grid.
npx purgecss --config purgecss.config.js --output dist/style.min.css
(3) Use Minified Version via CDN
<!-- Always use .min.css / .min.js in production -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
Output: Bootstrap 5.3 styled components (e.g., buttons, cards, carousels, collapses), using the default Bootstrap theme (light) and responsive grid.
4. JavaScript Optimization
(1) On-Demand Component Import
// Import only the needed JS components
import Alert from 'bootstrap/js/dist/alert'
import Button from 'bootstrap/js/dist/button'
import Carousel from 'bootstrap/js/dist/carousel'
import Collapse from 'bootstrap/js/dist/collapse'
import Dropdown from 'bootstrap/js/dist/dropdown'
import Modal from 'bootstrap/js/dist/modal'
import Offcanvas from 'bootstrap/js/dist/offcanvas'
// Initialize all tooltips
document.querySelectorAll('[data-bs-toggle="tooltip"]')
.forEach(el => new bootstrap.Tooltip(el))
Output: Bootstrap 5.3 styled components (e.g., buttons, cards, carousels, collapses), using the default Bootstrap theme (light) and responsive grid.
(2) Defer Non-Critical JS
<!-- Defer non-critical JS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" defer></script>
Output: Bootstrap 5.3 styled components (e.g., buttons, cards, carousels, collapses), using the default Bootstrap theme (light) and responsive grid.
(3) On-Demand Icon Import
<!-- If using few icons, use inline SVG instead of icon font -->
<svg class="bi" width="16" height="16" fill="currentColor">
<use href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/bootstrap-icons.svg#house"/>
</svg>
<!-- Or download needed SVGs locally to avoid CDN requests -->
Output: Bootstrap 5.3 styled components (e.g., buttons, cards, carousels, collapses), using the default Bootstrap theme (light) and responsive grid.
5. Image Optimization
<!-- Always use width + height to prevent layout shift -->
<img src="photo.webp" width="800" height="450" class="img-fluid" alt="Photo"
loading="lazy">
<!-- Use modern formats -->
<picture>
<source srcset="photo.avif" type="image/avif">
<source srcset="photo.webp" type="image/webp">
<img src="photo.jpg" class="img-fluid" alt="Photo">
</picture>
Output: Bootstrap 5.3 styled components (e.g., buttons, cards, carousels, collapses), using the default Bootstrap theme (light) and responsive grid.
6. Build and Deployment
(1) Production Build Process
// package.json
{
"scripts": {
"dev": "sass scss/custom.scss:dist/style.css --watch",
"build:css": "sass scss/custom.scss:dist/style.css --style compressed",
"build:purge": "purgecss --config purgecss.config.js --output dist/style.min.css",
"build": "npm run build:css && npm run build:purge",
"serve": "npx live-server --port=3000"
}
}
npm run build # Compile + purge
npm run serve # Local dev server
(2) Deployment Checklist
| Item | Check Points | Tools |
|---|---|---|
| CSS | Compressed, Purged, Critical CSS inlined | PurgeCSS, Critical |
| JS | Compressed, On-demand loading, defer | terser, webpack |
| Images | Compressed, webp/avif, lazy loading | sharp, squoosh |
| Fonts | Preloaded, font-display: swap | @font-face |
| Caching | CDN cache, ETag, Cache-Control | Cloudflare, Nginx |
| Analysis | Lighthouse score >= 90 | Lighthouse |
(3) Lighthouse Targets
| Metric | Target |
|---|---|
| First Contentful Paint | < 1.5s |
| Largest Contentful Paint | < 2.5s |
| Total Blocking Time | < 200ms |
| Cumulative Layout Shift | < 0.1 |
| Speed Index | < 3.0s |
7. Bootstrap vs Tailwind Selection Review
| Dimension | Bootstrap | Tailwind CSS |
|---|---|---|
| Learning Curve | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| Development Speed | Fast (Ready-to-use components) | Medium (Need to combine utilities) |
| File Size | 28KB gzip (Full) | On-demand compilation, usually < 10KB |
| Customization Ability | Medium (Sass variables) | High (Design system) |
| Component Ecosystem | 70+ built-in | None (Needs Headless UI) |
| Upgrade Cost | Low (Semantic classes) | Medium (Class changes) |
| Suitable Projects | Admin panels, MVPs, SME websites | Design systems, Brand customization |
8. Optimization Practical Examples
▶ Example: PurgeCSS Configuration Optimization
// purgecss.config.js — Full production configuration
module.exports = {
content: [
'./src/**/*.html',
'./src/**/*.js',
'./src/**/*.php',
],
css: [
'./dist/style.css',
'./node_modules/bootstrap-icons/font/bootstrap-icons.css',
],
safelist: {
standard: [
// Bootstrap dynamic classes
/^bs-/, // All Bootstrap CSS variables
/^data-bs-/, // All data attributes
'active', 'show', 'fade', 'collapsing',
'modal-open', 'modal-backdrop',
'carousel-item-start', 'carousel-item-end',
'tooltip', 'popover', 'toast',
/^btn-/, // Button variant classes
/^bg-/, // Background classes
/^text-/, // Text color classes
/^border-/, // Border classes
/^alert-/, // Alert variants
/^badge-/, // Badge variants
],
deep: [
/^theme$/,
],
greedy: [
/dark/,
],
},
blocklist: [
/^bi-/, // Optionally remove unused BI icons
],
variables: true,
};
// Run: npx purgecss --config purgecss.config.js --output dist/style.purged.css
Output: Bootstrap 5.3 styled components (e.g., buttons, cards, carousels, collapses), using the default Bootstrap theme (light) and responsive grid.
// package.json scripts for optimized build
{
"scripts": {
"dev": "sass scss/custom.scss dist/style.css --watch",
"build:css": "sass scss/custom.scss dist/style.css --style compressed",
"build:purge": "purgecss --config purgecss.config.js --output dist/style.purged.css",
"build:copy": "cp dist/style.purged.css dist/style.min.css",
"build": "npm run build:css && npm run build:purge && npm run build:copy",
"build:all": "npm run build && npx terser dist/script.js -o dist/script.min.js",
"serve": "npx live-server --port=3000 --no-browser"
}
}
▶ Example: Lighthouse Optimization Checklist
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- SEO Meta -->
<title>Optimized Bootstrap Page</title>
<meta name="description" content="Lighthouse score 95+ page built with Bootstrap.">
<!-- Preconnect to CDN -->
<link rel="preconnect" href="https://cdn.jsdelivr.net">
<link rel="dns-prefetch" href="https://cdn.jsdelivr.net">
<!-- Critical CSS inline (load first) -->
<style>
/* Minimal critical CSS for above-the-fold content */
.hero { background: #0d6efd; color: #fff; padding: 4rem 0; }
.container { max-width: 1140px; margin: 0 auto; padding: 0 1rem; }
@media (max-width: 768px) { .hero { padding: 2rem 0; } }
</style>
<!-- Non-critical CSS (deferred) -->
<link rel="preload" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"></noscript>
<!-- Preload hero image -->
<link rel="preload" href="hero.webp" as="image" fetchpriority="high">
</head>
<body>
<div class="hero">
<div class="container">
<h1 class="display-4 fw-bold">Optimized Bootstrap</h1>
<p class="lead mb-4">Lighthouse score: Performance 98, Accessibility 100, Best Practices 95</p>
<a href="#" class="btn btn-light btn-lg px-4">Get Started</a>
</div>
</div>
<div class="container py-5">
<div class="row g-4">
<!-- Cards with lazy loaded images -->
<div class="col-md-4">
<div class="card p-4 h-100">
<img src="placeholder.svg" data-src="card1.webp" class="card-img-top lazy" alt="Card 1" width="400" height="250" loading="lazy">
<h5 class="card-title mt-2">Optimized Card</h5>
<p class="card-text text-body-secondary">Lazy-loaded WebP image, proper aspect ratio.</p>
</div>
</div>
<div class="col-md-4">
<div class="card p-4 h-100">
<img src="placeholder.svg" data-src="card2.webp" class="card-img-top lazy" alt="Card 2" width="400" height="250" loading="lazy">
<h5 class="card-title mt-2">Fast Loading</h5>
<p class="card-text text-body-secondary">Font display swap enabled.</p>
</div>
</div>
<div class="col-md-4">
<div class="card p-4 h-100">
<img src="placeholder.svg" data-src="card3.webp" class="card-img-top lazy" alt="Card 3" width="400" height="250" loading="lazy">
<h5 class="card-title mt-2">Accessible</h5>
<p class="card-text text-body-secondary">100 Accessibility score guaranteed.</p>
</div>
</div>
</div>
</div>
<!-- Deferred Bootstrap JS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" defer></script>
<!-- Lazy load images -->
<script>
document.addEventListener('DOMContentLoaded', function() {
const lazyImages = document.querySelectorAll('.lazy');
if ('IntersectionObserver' in window) {
const observer = new IntersectionObserver(function(entries) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.classList.remove('lazy');
observer.unobserve(img);
}
});
});
lazyImages.forEach(function(img) { observer.observe(img); });
}
});
</script>
</body>
</html>
Output: Bootstrap 5.3 styled components (e.g., buttons, cards, carousels, collapses), using the default Bootstrap theme (light) and responsive grid.
▶ Example: CDN Multi-Source Fallback Loading
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CDN with Fallback</title>
<!-- Primary CDN: jsDelivr -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
id="bootstrap-css"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
crossorigin="anonymous">
<!-- Fallback: if primary CDN fails, load from unpkg -->
<script>
window.onload = function() {
var css = document.getElementById('bootstrap-css');
if (css && !css.sheet) {
var fallback = document.createElement('link');
fallback.rel = 'stylesheet';
fallback.href = 'https://unpkg.com/bootstrap@5.3.3/dist/css/bootstrap.min.css';
document.head.appendChild(fallback);
}
};
</script>
</head>
<body>
<div class="container py-5">
<h1>CDN Multi-Source Fallback</h1>
<div class="alert alert-success">
<i class="bi bi-check-circle-fill me-2"></i> Bootstrap loaded successfully!
</div>
<p class="text-body-secondary">If jsDelivr is down, automatically falls back to unpkg.</p>
<div class="card p-4 shadow-sm">
<h5>CDN Source Chain</h5>
<ol class="mb-0">
<li class="mb-1"><strong>Primary:</strong> cdn.jsdelivr.net</li>
<li class="mb-1"><strong>Fallback 1:</strong> unpkg.com</li>
<li><strong>Fallback 2:</strong> cdnjs.cloudflare.com</li>
</ol>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"
crossorigin="anonymous"
defer></script>
<script>
// JS fallback
if (typeof bootstrap === 'undefined') {
var script = document.createElement('script');
script.src = 'https://unpkg.com/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js';
script.defer = true;
document.body.appendChild(script);
}
</script>
</body>
</html>
Output: Bootstrap 5.3 styled components (e.g., buttons, cards, carousels, collapses), using the default Bootstrap theme (light) and responsive grid.
▶ Example: Complete Build Script
// package.json — Full build pipeline
{
"name": "bootstrap-production-build",
"version": "1.0.0",
"scripts": {
"clean": "rimraf dist",
"sass:compile": "sass scss/custom.scss:dist/css/style.css --style compressed",
"sass:watch": "sass scss/custom.scss:dist/css/style.css --watch",
"prefix": "postcss dist/css/style.css --use autoprefixer -o dist/css/style.prefixed.css",
"purge": "purgecss --config purgecss.config.js --output dist/css/style.min.css",
"js:bundle": "esbuild src/js/main.js --bundle --minify --outfile=dist/js/main.min.js",
"img:min": "imagemin src/images/* --out-dir=dist/images",
"copy:html": "cp src/*.html dist/",
"build:dev": "npm run clean && npm run sass:compile && npm run copy:html",
"build:prod": "npm run build:dev && npm run prefix && npm run purge && npm run js:bundle && npm run img:min",
"serve": "lite-server --baseDir='dist'",
"deploy": "npm run build:prod && gh-pages -d dist"
},
"devDependencies": {
"autoprefixer": "^10.4.17",
"esbuild": "^0.20.0",
"imagemin-cli": "^7.0.0",
"lite-server": "^2.6.1",
"postcss": "^8.4.33",
"postcss-cli": "^11.0.0",
"purgecss": "^6.0.0",
"rimraf": "^5.0.5",
"sass": "^1.70.0"
},
"dependencies": {
"bootstrap": "^5.3.3",
"bootstrap-icons": "^1.11.3"
}
}
# Full build commands
# Development
npm run build:dev # Compile SCSS + copy HTML
# Production
npm run build:prod # Compile → Autoprefix → Purge → Minify JS → Optimize images
# Local preview
npm run serve # Serve dist/ with auto-reload
# Deploy to GitHub Pages
npm run deploy # Build + publish
# Individual steps
npx sass scss/custom.scss dist/css/style.css --style compressed
npx postcss dist/css/style.css --use autoprefixer -o dist/css/style.prefixed.css
npx purgecss --css dist/css/style.prefixed.css --content dist/**/*.html --output dist/css/
npx esbuild src/js/main.js --bundle --minify --outfile=dist/js/main.min.js
(1) Optimization Priority Matrix
graph TD
A[Performance Optimization Priority] --> B[🛡️ P0: Critical]
A --> C[🔥 P1: High]
A --> D[⚡ P2: Medium]
A --> E[📋 P3: Low]
B --> B1[Enable Gzip/Brotli compression]
B --> B2[Optimize image format WebP/AVIF]
B --> B3[Remove unused CSS]
B --> B4[Enable CDN cache]
C --> C1[Defer non-critical JS]
C --> C2[Inline critical CSS]
C --> C3[Preconnect to third-party domains]
D --> D1[Font display:swap]
D --> D2[Image lazy loading]
D --> D3[Resource Preload/Prefetch]
E --> E1[Service Worker cache]
E --> E2[HTTP/2 Server Push]
E --> E3[Skeleton screen loading]
Output: Bootstrap 5.3 styled components (e.g., buttons, cards, carousels, collapses), using the default Bootstrap theme (light) and responsive grid.
(2) Optimization Priority Matrix Table
| Priority | Optimization Item | Estimated Benefit | Implementation Difficulty | Lighthouse Metric |
|---|---|---|---|---|
| P0 (Critical) | Enable Gzip/Brotli | Reduce size by 70-80% | Low (Server config) | FCP, LCP |
| P0 (Critical) | WebP/AVIF image format | Reduce image size by 30-50% | Medium (Build script) | LCP |
| P0 (Critical) | PurgeCSS remove unused styles | Reduce CSS by 60-80% | Low (Config file) | FCP |
| P1 (High) | Inline critical CSS | Reduce first-screen render blocking | Medium (Needs tool) | FCP |
| P1 (High) | Defer JS loading | Reduce JS blocking | Low (Add attribute) | TBT |
| P1 (High) | CDN pre-warming | Speed up first visit | Medium (Manual action) | LCP |
| P2 (Medium) | Font display:swap | Eliminate FOIT | Low (CSS property) | CLS |
| P2 (Medium) | Image lazy loading | Reduce initial load | Low (Add attribute) | LCP |
| P3 (Low) | Service Worker cache | Ultra-fast second visit | High (Need to write SW) | Reuse metrics |
(3) Deployment Platform Comparison Table
| Platform | Free Quota | Custom Domain | HTTPS | Deployment Method | CI/CD | Suitable Scenario |
|---|---|---|---|---|---|---|
| GitHub Pages | Unlimited (public repos) | ✅ | ✅ | git push |
GitHub Actions | Personal/open-source projects |
| Netlify | 100GB/month | ✅ | ✅ | Git connection / CLI | Automatic | Static sites, Jamstack |
| Vercel | 100GB/month | ✅ | ✅ | Git connection / CLI | Automatic | Next.js, frontend projects |
| Cloudflare Pages | Unlimited | ✅ | ✅ | Git connection / CLI | Automatic | Global CDN priority |
| AWS S3 + CloudFront | Pay-as-you-go | ✅ | ✅ | CLI / SDK | Configurable | Enterprise production |
| Aliyun OSS + CDN | Pay-as-you-go | ✅ | ✅ | CLI / SDK | Configurable | China region users |
❓ Frequently Asked Questions
btn-${color}) need to be added to the safelist. It is recommended to list all possibly dynamically appearing class names in the PurgeCSS configuration's safelist.📖 Summary
- CSS optimization: On-demand Sass compilation + PurgeCSS redundancy removal, use
.minversion via CDN - JS optimization: On-demand component import +
deferlazy loading - Image optimization:
loading="lazy"+ WebP/AVIF format + fixed width and height - Build process:
sasscompile >purgecssclean > deploy - Lighthouse targets: FCP < 1.5s, LCP < 2.5s, CLS < 0.1
📝 Homework
- ⭐ Run a Lighthouse audit on an existing Bootstrap project, record FCP, LCP, and CLS metrics, then optimize item by item until all meet the targets.
- ⭐⭐ Configure PurgeCSS: Run PurgeCSS on an HTML file using Bootstrap, and compare the size difference between purged and unpurged CSS.
- ⭐⭐⭐ Create a complete
package.jsonscript containing three commands: dev (watch), build (sass + purge), and serve.
Previous Lesson: Dark Mode



