404 Not Found

404 Not Found


nginx

Performance Optimization and Build Deployment

1. Course Introduction

(1) Prerequisites

(2) 🎯 What You Will Learn


(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

100%
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)

SCSS
// 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";
▶ Try it Yourself

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:

BASH
npm install -D purgecss
JAVASCRIPT
// purgecss.config.js
module.exports = {
  content: ['.//*.html', './/*.js'],
  css: ['./dist/style.css'],
  safelist: ['show', 'active', 'fade', 'collapse', 'modal-open']
}
▶ Try it Yourself

Output: Bootstrap 5.3 styled components (e.g., buttons, cards, carousels, collapses), using the default Bootstrap theme (light) and responsive grid.

BASH
npx purgecss --config purgecss.config.js --output dist/style.min.css

(3) Use Minified Version via CDN

HTML
<!-- 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>
▶ Try it Yourself

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

JAVASCRIPT
// 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))
▶ Try it Yourself

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

HTML
<!-- Defer non-critical JS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" defer></script>
▶ Try it Yourself

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

HTML
<!-- 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 -->
▶ Try it Yourself

Output: Bootstrap 5.3 styled components (e.g., buttons, cards, carousels, collapses), using the default Bootstrap theme (light) and responsive grid.


5. Image Optimization

HTML
<!-- 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>
▶ Try it Yourself

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

JSON
// 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"
  }
}
BASH
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

JAVASCRIPT
// 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
▶ Try it Yourself

Output: Bootstrap 5.3 styled components (e.g., buttons, cards, carousels, collapses), using the default Bootstrap theme (light) and responsive grid.

JSON
// 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

HTML
<!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>
▶ Try it Yourself

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

HTML
<!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>
▶ Try it Yourself

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

JSON
// 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"
  }
}
BASH
# 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

100%
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

Q Will PurgeCSS accidentally delete dynamic classes?
A Possibly. Dynamic classes (like JS-concatenated 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.
Q Does Bootstrap 5 require Babel/Webpack to use?
A No. The CDN method is fully usable (the first 19 lessons used it). Build tools like Webpack/Vite are only for Sass customization and on-demand compilation—they are auxiliary tools, not requirements.
Q What to note when switching from CDN to Sass deployment?
A (1) Replace all CDN links with locally compiled CSS; (2) Ensure JS still references CDN or local bundle; (3) Verify all component functionalities are normal; (4) Compare page styles before and after for consistency.
Q In production, use CDN or npm build?
A Both have pros and cons: CDN approach—Pros: No build tools needed, leverages CDN cache, shared cache across multiple sites; Cons: No customization, external dependency risk. npm + build approach—Pros: Fully customizable, PurgeCSS capable, independent deployment; Cons: Requires build process, need to handle caching yourself. Recommendation: Use CDN for prototypes, npm + build for official projects.
Q How does HTTP/2 help optimize a Bootstrap project?
A HTTP/2's Multiplexing feature allows multiple small files to load faster in parallel, so there's no need to combine all CSS into one file—you can split modules on demand. Also, HTTP/2's Server Push can proactively push critical CSS. However, Bootstrap itself is only 28KB gzip, which is small; HTTP/2's benefits are more evident in large projects.

📖 Summary


📝 Homework

  1. ⭐ 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.
  2. ⭐⭐ Configure PurgeCSS: Run PurgeCSS on an HTML file using Bootstrap, and compare the size difference between purged and unpurged CSS.
  3. ⭐⭐⭐ Create a complete package.json script containing three commands: dev (watch), build (sass + purge), and serve.

Previous Lesson: Dark Mode

Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏