webpack-vite

Installation
SKILL.md

Webpack and Vite Reference

Vite Configuration

// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';

export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
      '@components': path.resolve(__dirname, './src/components'),
    },
  },
  server: { port: 3000, open: true, strictPort: true },
  build: {
    outDir: 'dist',
    sourcemap: true,
    target: 'esnext',
    minify: 'esbuild',               // or 'terser' for drop_console
    rollupOptions: {
      output: {
        manualChunks: { vendor: ['react', 'react-dom'], router: ['react-router-dom'] },
      },
    },
  },
  optimizeDeps: {
    include: ['lodash-es', 'axios'],  // force pre-bundling
    exclude: ['your-local-package'],
  },
  css: {
    modules: { localsConvention: 'camelCaseOnly' },
    preprocessorOptions: { scss: { additionalData: `@use "@/styles/variables" as *;` } },
  },
});

Vite Environment Variables

# .env / .env.local / .env.development / .env.production / .env.[mode]
# Only VITE_ prefixed vars are exposed to client code
VITE_API_URL=https://api.example.com
DB_PASSWORD=secret                     # NOT exposed to client
const apiUrl = import.meta.env.VITE_API_URL;
const isDev = import.meta.env.DEV;       // boolean
const mode = import.meta.env.MODE;       // 'development' | 'production' | custom

// Type declarations (env.d.ts)
/// <reference types="vite/client" />
interface ImportMetaEnv { readonly VITE_API_URL: string }

Vite Plugins

import react from '@vitejs/plugin-react';           // Babel-based
import reactSWC from '@vitejs/plugin-react-swc';    // SWC-based (faster)
import vue from '@vitejs/plugin-vue';
import svgr from 'vite-plugin-svgr';                // SVG as React components
import { VitePWA } from 'vite-plugin-pwa';
import legacy from '@vitejs/plugin-legacy';          // IE11 / older browser support
import { visualizer } from 'rollup-plugin-visualizer'; // bundle analysis

export default defineConfig({
  plugins: [
    reactSWC(),
    svgr(),
    VitePWA({ registerType: 'autoUpdate', workbox: { globPatterns: ['**/*.{js,css,html,ico,png,svg}'] } }),
    legacy({ targets: ['defaults', 'not IE 11'] }),
    visualizer({ open: true, gzipSize: true, brotliSize: true }),
  ],
});

Vite Dev Server and Proxy

export default defineConfig({
  server: {
    proxy: {
      '/api': { target: 'http://localhost:4000', changeOrigin: true, rewrite: (p) => p.replace(/^\/api/, '') },
      '/ws': { target: 'ws://localhost:4000', ws: true },
    },
    https: { key: './certs/key.pem', cert: './certs/cert.pem' },
    cors: true,
    fs: { allow: ['../..'] },            // monorepo: serve files outside root
  },
});

Webpack 5 Configuration

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  mode: 'production',
  entry: { main: './src/index.tsx', admin: './src/admin.tsx' },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[contenthash].js',
    chunkFilename: '[name].[contenthash].chunk.js',
    clean: true,
    publicPath: '/',
  },
  resolve: {
    extensions: ['.tsx', '.ts', '.js', '.jsx'],
    alias: { '@': path.resolve(__dirname, 'src') },
  },
  module: {
    rules: [
      { test: /\.(ts|tsx|js|jsx)$/, exclude: /node_modules/, use: { loader: 'babel-loader',
          options: { presets: ['@babel/preset-env', '@babel/preset-react', '@babel/preset-typescript'] } } },
      { test: /\.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader'] },
      { test: /\.module\.css$/, use: [MiniCssExtractPlugin.loader,
          { loader: 'css-loader', options: { modules: true } }, 'postcss-loader'] },
      { test: /\.s[ac]ss$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader'] },
      { test: /\.(png|jpg|gif|svg|webp)$/, type: 'asset', parser: { dataUrlCondition: { maxSize: 8 * 1024 } } },
      { test: /\.(woff|woff2|eot|ttf|otf)$/, type: 'asset/resource' },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({ template: './public/index.html', minify: { collapseWhitespace: true } }),
    new MiniCssExtractPlugin({ filename: 'css/[name].[contenthash].css' }),
  ],
};
// Note: Webpack 5 asset modules replace file-loader, url-loader, and raw-loader.

Webpack Plugins

const { DefinePlugin, ProvidePlugin } = require('webpack');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');

module.exports = {
  plugins: [
    new DefinePlugin({
      'process.env.API_URL': JSON.stringify(process.env.API_URL),
      __DEV__: JSON.stringify(process.env.NODE_ENV === 'development'),
    }),
    new ProvidePlugin({ React: 'react' }),
    new CopyWebpackPlugin({ patterns: [{ from: 'public/assets', to: 'assets' }] }),
    new BundleAnalyzerPlugin({ analyzerMode: 'static', openAnalyzer: false }),
  ],
};

Code Splitting

// Dynamic import -- creates a separate chunk loaded on demand
const LazyComponent = React.lazy(() => import('./HeavyComponent'));
const Admin = React.lazy(() => import(/* webpackChunkName: "admin" */ './AdminPanel'));

// Webpack splitChunks
module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all',
      maxInitialRequests: 20,
      minSize: 20000,
      cacheGroups: {
        vendor: { test: /[\\/]node_modules[\\/]/, name: 'vendors', priority: -10 },
        commons: { minChunks: 2, priority: -20, reuseExistingChunk: true },
      },
    },
    runtimeChunk: 'single',
  },
};

// Vite manual chunks
export default defineConfig({
  build: {
    rollupOptions: {
      output: {
        manualChunks(id) {
          if (id.includes('node_modules')) {
            if (id.includes('react')) return 'react-vendor';
            return 'vendor';
          }
        },
      },
    },
  },
});

Tree Shaking

// package.json -- mark as side-effect-free for tree shaking
{ "sideEffects": false }
// Or specify files with side effects:
{ "sideEffects": ["*.css", "*.scss", "./src/polyfills.ts"] }
import { debounce } from 'lodash-es';     // tree-shakeable (ESM)
const { debounce } = require('lodash');    // NOT tree-shakeable (CJS), bundles everything
// Webpack: set mode 'production' to enable terser + dead code elimination
// Vite: tree shaking via Rollup is on by default in production

Bundle Analysis

# Webpack
npx webpack --profile --json > stats.json && npx webpack-bundle-analyzer stats.json
# Or use BundleAnalyzerPlugin (see Webpack Plugins section)

# Vite -- use rollup-plugin-visualizer (see Vite Plugins section)

Webpack Dev Server

module.exports = {
  devServer: {
    port: 3000,
    hot: true,
    historyApiFallback: true,            // SPA routing fallback
    compress: true,
    proxy: [{ context: ['/api'], target: 'http://localhost:4000', changeOrigin: true,
              pathRewrite: { '^/api': '' } }],
    https: true,
    static: { directory: path.join(__dirname, 'public') },
  },
};

Production Optimization

// Webpack
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const CompressionPlugin = require('compression-webpack-plugin');

module.exports = {
  mode: 'production',
  devtool: 'source-map',                // 'hidden-source-map' to hide from users
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({ terserOptions: { compress: { drop_console: true, drop_debugger: true } } }),
      new CssMinimizerPlugin(),
    ],
  },
  plugins: [
    new CompressionPlugin({ algorithm: 'gzip', test: /\.(js|css|html|svg)$/, threshold: 10240 }),
  ],
};
// Vite production
export default defineConfig({
  build: {
    sourcemap: 'hidden',
    minify: 'terser',
    terserOptions: { compress: { drop_console: true } },
    cssCodeSplit: true,
    assetsInlineLimit: 4096,             // inline assets < 4KB as base64
    chunkSizeWarningLimit: 500,
  },
});

CSS Handling

// postcss.config.js -- shared by both Webpack and Vite
module.exports = {
  plugins: {
    'tailwindcss': {},
    'autoprefixer': {},
    'cssnano': process.env.NODE_ENV === 'production' ? {} : false,
  },
};
// Vite: install sass and import .scss directly -- no loader config needed
// Webpack: add sass-loader to module.rules (see Webpack 5 Configuration)

Migration from Webpack to Vite

npm install -D vite @vitejs/plugin-react    # 1. install
# 2. Create vite.config.ts                  # see "Vite Configuration" section
# 3. Move index.html to project root, add: <script type="module" src="/src/main.tsx"></script>
# 4. Update package.json scripts: "dev": "vite", "build": "tsc && vite build", "preview": "vite preview"
Webpack Vite
require() / module.exports import / export (ESM only)
process.env.X import.meta.env.VITE_X
file-loader / url-loader Native static asset handling
webpack.DefinePlugin define option in vite.config.ts
webpackChunkName comments rollupOptions.output.manualChunks
require.context() import.meta.glob()
webpack-dev-server proxy server.proxy in vite config

Monorepo Bundling

// Vite monorepo
export default defineConfig({
  resolve: { alias: { '@shared/ui': path.resolve(__dirname, '../../packages/ui/src') } },
  optimizeDeps: { include: ['@shared/ui'] },
  server: { fs: { allow: ['../..'] } },
});

// Webpack monorepo
module.exports = {
  resolve: { alias: { '@shared/ui': path.resolve(__dirname, '../../packages/ui/src') }, symlinks: false },
  module: { rules: [{
    test: /\.(ts|tsx)$/,
    include: [path.resolve(__dirname, 'src'), path.resolve(__dirname, '../../packages')],
    use: 'babel-loader',
  }] },
};

Performance Budgets

// Webpack -- built-in performance hints
module.exports = {
  performance: {
    hints: 'error',                      // 'warning' | 'error' | false
    maxAssetSize: 250000,                // 250KB per asset
    maxEntrypointSize: 400000,           // 400KB per entry point
    assetFilter: (file) => !/\.map$/.test(file),
  },
};
# size-limit -- CI-friendly, works with both Webpack and Vite
npm install -D size-limit @size-limit/preset-app
# package.json: "size-limit": [{ "path": "dist/assets/*.js", "limit": "200 KB", "gzip": true }]
npx size-limit
Related skills

More from 1mangesh1/dev-skills-collection

Installs
1
GitHub Stars
3
First Seen
Apr 14, 2026