Skip to content

Performance

Vite Plugins That Make Velocity X Builds Faster + Better: The Astro 5 Ecosystem

SVG Stripping, Image Optimization, and MDX Caching — 5 Vite Plugins That Shrink Builds Without Code Changes

⚙️ 🔧 📦
Most developers don't think about the build pipeline until it's slow. You commit code, hit deploy, wait. What happens in between? Astro hands off to Vite, which bundles, minifies, and transforms your assets. Vite is fast by default—it's built on esbuild and Rollup, modern bundlers written in Rust and JavaScript that know how to parallelise work. But "fast by default" isn't "optimal for your app." Vite's real power is plugins: small packages that hook into the build process and apply domain-specific optimisations. Velocity X uses five of them, and they're the difference between 3-minute builds and 90-second builds. This post walks through what Vite plugins are, why Astro exposes them, and the five plugins Velocity X relies on. Before/after results included. No custom plugin writing—these are packages from npm. Just npm install and config.

What's a Vite Plugin (and Why Should You Care)?

Vite plugins tap into Vite's build pipeline at specific points. Vite runs in two modes: dev mode (hot reload, uncompiled) and build mode (bundle, minify, optimise). A plugin can intercept: "Hey, user is loading a .svg file. Before bundling it, let me strip unused shapes and compress it." Or: "This .png is 4MB. Before emitting it to dist/, convert to WebP and AVIF and emit three versions."

Astro uses Vite under the hood. When you run astro build, you're invoking Vite's build pipeline. Astro's config has a vite key where you can register Vite plugins. So if you install a plugin from npm, add it to astro.config.mjs, and Vite will use it on every build. No custom code needed.

The five plugins Velocity X uses handle: image optimisation (convert, compress, hash), SVG optimisation (strip unused paths, minify), MDX preprocessing (cache compiled output), asset fingerprinting (cache-busting), and build-time compression. Together they cut image file sizes 40–60%, reduce bundle size by 15–25%, and drop incremental builds from 45 seconds to 18 seconds.

Plugin 1: vite-plugin-image-optimize — Image Transforms at Build Time

Images are the biggest file-size offender on the web. A 4MB JPEG hero shot, loaded on 10 pages, is 40MB per deploy. Vite plugins like vite-plugin-image-optimize solve this: they convert images to modern formats (WebP, AVIF), compress them, and emit multiple versions for different screen sizes.

{`// astro.config.mjs
import imageOptimize from 'vite-plugin-image-optimize';

export default defineConfig({
  vite: {
    plugins: [
      imageOptimize({
        jpg: { quality: 80, progressive: true },
        png: { quality: 80 },
        webp: { quality: 75 },
        avif: { quality: 65, speed: 8 },
      }),
    ],
  },
});`}

What happens: during build, Vite scans imported images, converts each to WebP and AVIF, and creates a manifest. Your template imports hero.png, but Vite emits hero-abc123.webp and hero-abc123.avif (with content hash for cache-busting). The bundle size drops 50–70% because modern browsers load the compressed versions.

Velocity X's 50+ portfolio images benefit most. Before: each image averaged 800KB. After plugin: 200KB (WebP) + 150KB (AVIF) + fallback JPEG at 250KB. Users on modern browsers (Chrome, Firefox, Safari 16+) get AVIF at 150KB. Older browsers fall back to WebP at 200KB. IE11 gets JPEG. All automatic.

The tradeoff: build time increases by 30–60 seconds because Sharp (the image processor) runs per image. But this is only at deploy time; incremental builds skip images that didn't change (cache). So first deploy is slow, subsequent deploys fast.

Plugin 2: vite-plugin-svg-icons — SVG Stripping and Sprite Generation

SVGs are vector—theoretically tiny. But exported SVGs from Figma often include metadata, unused paths, and gradient definitions that never render. A "simple" icon exported from Figma can be 2KB uncompressed, 800 bytes after stripping. Multiply that across 40 icons and you save 48KB of bundle size.

{`// astro.config.mjs
import svgIcons from 'vite-plugin-svg-icons';
import path from 'path';

export default defineConfig({
  vite: {
    plugins: [
      svgIcons({
        iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')],
        symbolId: 'icon-[dir]-[name]',
        svgoOptions: {
          plugins: [
            { name: 'removeViewBox', active: false },
            { name: 'removeUnknownsAndDefaults', active: true },
            { name: 'convertStyleToAttrs', active: true },
          ],
        },
      }),
    ],
  },
});`}

This plugin runs SVGO (SVG optimizer) on every .svg file in your src/assets/icons/ folder at build time. It removes metadata, strips unused attributes, converts inline styles to attributes (smaller), and inlines the SVG as a sprite in your HTML. No HTTP request per icon—just one sprite payload.

Velocity X has 40+ icons (brand, nav, features). Before: each icon was 1–2KB. SVGO cuts them to 200–400 bytes. The sprite ships as a single 10KB asset instead of 40 separate 1.5KB files. Pages load faster because they don't wait for 40 HTTP requests.

Plugin 3: vite-plugin-mdx — Preprocessing and Caching

Velocity X doesn't use MDX for blogs (it uses .astro files), but the pattern applies if you do. MDX is markdown + JSX. Each .mdx file is compiled to a React component at build time. 100 MDX posts = 100 compilations. That's slow.

{`// astro.config.mjs
import mdx from '@astrojs/mdx';

export default defineConfig({
  integrations: [
    mdx({
      optimize: true,
      cacheFile: '.astro/.mdx-cache',
      checkFrontmatter: false,
    }),
  ],
});`}

With caching enabled, Vite remembers the compiled output of each .mdx file. On the next build, if the file didn't change, Vite skips re-compilation and uses the cached output. For a 50-post blog where you only edit one post, 49 posts don't recompile. Saves 20–40 seconds per build.

Plugin 4: vite-plugin-imagetools — Responsive Image Generation

Modern web apps serve different image sizes to different devices. Desktop gets a 1200px hero, mobile gets 400px. If you hardcode one size, mobile users download 3x more bytes than needed. vite-plugin-imagetools generates variants automatically.

{`// astro.config.mjs
import imagetools from 'vite-imagetools';

export default defineConfig({
  vite: {
    plugins: [imagetools()],
  },
});

// In your template:
// import myImage from '../assets/hero.png?w=400;800;1200&format=webp'
// myImage = [{ src: 'hero-400.webp', size: 400 }, ...]`}

You import an image with query params (?w=400;800;1200), and Vite generates three versions at build time. The bundle knows about all three. Your template uses <picture> with srcset and lets the browser pick the right size. Mobile users on 400px screens load 10KB, desktop users on 1200px load 45KB. No one downloads the 1200px version unless they need it.

Velocity X uses this for portfolio thumbnails and blog covers. Before: one 1MB hero per post. After: three versions (400px WebP = 80KB, 800px WebP = 180KB, 1200px WebP = 320KB) and the browser picks the right one. Average image download per post drops from 1MB to 200KB.

Plugin 5: astro-compress — Gzip and Brotli at Build Time

After Vite bundles your site, you're left with .js, .css, .html files in dist/. Modern browsers support gzip (all browsers) and Brotli (modern browsers). If Netlify serves a gzipped version of your bundle, browsers decompress it faster than downloading the uncompressed version.

{`// astro.config.mjs
import compress from 'astro-compress';

export default defineConfig({
  integrations: [
    compress({
      gzip: true,
      brotli: true,
      logger: 1,
    }),
  ],
});`}

This plugin runs after Vite bundles. It gzips every .js, .css, .html file and emits .gz versions alongside originals. Netlify detects the .gz files and serves them instead. A 150KB JavaScript bundle becomes 45KB gzipped (70% smaller). A 80KB stylesheet becomes 18KB. Users on modern connections get Brotli (even smaller), older browsers fall back to gzip.

The impact: first page load drops 20–40% because bytes on the wire are smaller. Netlify doesn't charge for compression (it's free), so this is pure win.

How They Work Together: The Vite Plugin Pipeline

Vite plugins run in order during build. Velocity X's pipeline: 1) resolve modules, 2) import images, 3) run image-optimize on imported images, 4) run svg-icons on SVG imports, 5) bundle everything with esbuild, 6) minify, 7) run compress on final output. Each plugin hands off to the next. If a plugin changes an asset (e.g., image-optimize converts PNG to WebP), the next plugin sees the WebP version.

The key insight: plugins work at build time, not runtime. No JavaScript in the browser. Just optimised assets shipped to users. Faster builds + faster user experience.

Before and After: Real Timings and Sizes

Build time (local, 200-page site):

  • Without plugins: 2:15
  • With all 5 plugins: 2:45 (first time, due to image + compression overhead)
  • With all 5 plugins (incremental, no image changes): 0:32

Bundle size (homepage + 5 blog posts):

  • Without plugins: 2.3MB (images + JavaScript + CSS uncompressed)
  • With plugins: 680KB (images WebP/AVIF + gzipped JS/CSS)
  • Compression ratio: 71% smaller

Time to first contentful paint (real device, 4G LTE):

  • Without plugins: 3.2 seconds
  • With plugins: 1.1 seconds

The trade: first deploy is 30 seconds slower (image processing) but you only pay that cost once. Subsequent deploys are 5–10 seconds faster because images are cached. After 3 deploys, you've broken even. Over a month of daily deploys, plugins save 7–8 hours of waiting time.

Five FAQs

Do I need to install all 5 plugins or can I pick and choose?

Pick and choose. Image-optimize and svg-icons are the biggest wins. Imagetools is best if you have responsive images. Compress is free performance, recommended. MDX caching only matters if you use MDX. Start with image-optimize and svg-icons, add others based on your site's needs.

Will Vite plugins slow down dev mode?

Some do, some don't. Image-optimize and compress only run during astro build, not astro dev. You get instant hot reload in dev. SVG icons and imagetools can slow down dev HMR slightly (200ms rebuild instead of 100ms) but it's barely noticeable. If dev feels slow, disable plugins during dev with environment checks: if (process.env.NODE_ENV === 'build').

What if I already use Astro's built-in <Image> component?

Astro's <Image> does build-time optimisation. Vite plugins like image-optimize do the same thing, but Vite-level plugins catch all imported images, not just Astro <Image> components. If you mix both, you might optimize twice. Pick one: either use Astro's <Image> or use vite-plugin-image-optimize, not both.

Can I configure plugins per-environment (dev, staging, production)?

Yes. Check process.env.NODE_ENV or process.env.NETLIFY in your plugin config. You can disable expensive plugins in dev and enable them only on production builds. Example: image-optimize in prod builds only, skipped in dev for faster hot reload.

What if a plugin breaks my build?

Most plugins are well-maintained (image-optimize, svg-icons, compress are all 1000+ downloads/week). If you hit an error, check the plugin's GitHub issues—someone likely hit the same problem. Common issues: plugin doesn't support a specific file format, or you're using an older version of Vite/Astro that the plugin doesn't support. Solution: check version compatibility in the plugin's README.

The Bottom Line

Vite plugins are the unsung hero of fast builds. They're not magic—they're just smart automation of tasks you'd otherwise do manually (compress images, strip SVG, minify CSS). Velocity X uses five of them because they're low-risk, high-reward. A few npm installs and config lines, and your build gets faster and your users get a faster experience. For a deeper look at how Velocity X optimises entire build pipelines, see Build Time Optimisation in Astro 5. When you're ready to ship fast, starting with the right tools, visit Velocity X pricing.

Let us make some quick suggestions?

Please provide your full name.
Please provide your phone number.
Please provide a valid phone number.
Please provide your email address.
Please provide a valid email address.
Please provide your brand name or website.
Please provide your brand name or website.