Skip to main content
rule

webpack — Cursor rule: what it does, how to install

This Cursor rule guides webpack configuration, caching, loaders, and code splitting. Use it when shaping a JavaScript build for development and production.

Install into Cursor · Manually: put the files in place All methods and platforms ↓
.cursor/rules/webpack.mdc
Open on GitHub

What webpack does

The rule recommends keeping shared webpack settings separate from development and production overrides. It covers filesystem caching, limiting loaders to project source files, and splitting bundles with splitChunks and dynamic imports. Its examples use webpack-merge to combine configurations, so projects need that dependency to follow the setup as written.

It also describes HtmlWebpackPlugin for adding bundles to an HTML template, DefinePlugin for build-time variables, and output.clean for clearing the output directory. These suggestions affect the build configuration; they do not replace checking how the project currently handles environment variables or assets.

The rule applies to js and jsx files. It includes guidance for development and production settings, including source maps and CSS extraction in the production example. Review the suggested settings against your project before adopting them.

What it helps with

  • separate webpack settings for development and production
  • scope Babel processing to project source files
  • split a large bundle into on-demand chunks
  • add generated bundles to an HTML template
  • clear stale files from the output directory

Example prompts for the agent

  • Split my webpack setup into shared, development, and production configurations.
  • Check that Babel runs on project source files, not node_modules.
  • Suggest splitChunks and dynamic imports for the large modules in this project.

How to install webpack

Manually: put the files in place

.cursor/rules/webpack.mdc

Frontmatter: description, globs, alwaysApply

Step by step, with commands for each platform: Cursor rules: .mdc files, four modes and what replaced .cursorrules

Questions about webpack

How do I install the webpack rule in Cursor?

Save the rule file at .cursor/rules/webpack.mdc.

What does the webpack rule do?

It offers guidance on webpack configuration, caching, loaders, plugins, and code splitting.

Which files does the rule apply to?

It targets files with the js and jsx extensions.

Source text

webpack.mdc · CC0-1.0
---
description: This guide provides opinionated, actionable best practices for configuring webpack, focusing on performance, maintainability, and modern development workflows in 2025.
globs: **/*.{js,jsx}
---
# webpack Best Practices

webpack remains the cornerstone of modern JavaScript application builds. Adhering to these definitive guidelines ensures your projects are performant, maintainable, and aligned with current best practices.

## 1. Configuration Structure

Always separate your webpack configurations by environment. Use `webpack-merge` to combine a common base with environment-specific overrides.

❌ BAD: Monolithic `webpack.config.js` with conditional logic.
```javascript
// webpack.config.js
const isProduction = process.env.NODE_ENV === 'production';

module.exports = {
  mode: isProduction ? 'production' : 'development',
  // ... lots of if/else logic
};
```

✅ GOOD: Modular configs with `webpack-merge`.
```javascript
// webpack.common.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    clean: true, // Always clean dist folder
  },
  plugins: [
    new HtmlWebpackPlugin({ template: './src/index.html' }),
  ],
  module: {
    rules: [
      {
        test: /\.js$/,
        include: path.resolve(__dirname, 'src'), // Target only your source
        loader: 'babel-loader',
      },
    ],
  },
};

// webpack.dev.js
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');

module.exports = merge(common, {
  mode: 'development',
  devtool: 'eval-cheap-module-source-map', // Fast source maps for dev
  output: {
    filename: '[name].bundle.js',
  },
  devServer: {
    static: './dist',
    hot: true, // Enable HMR
  },
});

// webpack.prod.js
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // For production CSS

module.exports = merge(common, {
  mode: 'production',
  devtool: 'source-map', // High-quality source maps for production debugging
  output: {
    filename: '[name].[contenthash].bundle.js', // Cache busting
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].[contenthash].css',
    }),
  ],
  optimization: {
    minimize: true, // Enable minification
    splitChunks: {
      chunks: 'all', // Aggressively split chunks
    },
  },
});
```

## 2. Performance Optimizations

Prioritize build speed and bundle size from the start.

### A. Caching

Enable persistent caching for faster incremental builds.

❌ BAD: No caching, slow rebuilds.
```javascript
module.exports = { /* ... */ };
```

✅ GOOD: Filesystem caching.
```javascript
module.exports = {
  cache: {
    type: 'filesystem',
    buildDependencies: {
      config: [__filename], // Invalidate cache if config changes
    },
  },
  // ...
};
```

### B. Loaders Scope

Apply loaders to the absolute minimum set of files. Exclude `node_modules` where possible.

❌ BAD: Applying Babel to `node_modules`.
```javascript
module.exports = {
  module: {
    rules: [{ test: /\.js$/, loader: 'babel-loader' }],
  },
};
```

✅ GOOD: Explicitly `include` your source, `exclude` `node_modules`.
```javascript
const path = require('path');
module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        include: path.resolve(__dirname, 'src'),
        exclude: /node_modules/, // Crucial for performance
        loader: 'babel-loader',
      },
    ],
  },
};
```

### C. Code Splitting

Leverage `optimization.splitChunks` and dynamic `import()` for smaller, on-demand bundles.

❌ BAD: Single large bundle for the entire application.
```javascript
// src/index.js
import { largeModuleA } from './largeModuleA';
import { largeModuleB } from './largeModuleB';
// ...
```

✅ GOOD: Dynamic imports with `splitChunks`.
```javascript
// webpack.prod.js (part of optimization)
module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all', // Automatically split vendor and common code
      minSize: 20000, // Minimum size for a chunk to be generated
      maxInitialRequests: 30, // Max number of parallel requests on initial load
      maxAsyncRequests: 30, // Max number of parallel requests for on-demand loading
      cacheGroups: {
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          priority: -10,
          reuseExistingChunk: true,
        },
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true,
        },
      },
    },
    runtimeChunk: 'single', // Separate runtime manifest
  },
  // ...
};

// src/index.js
const loadLargeModuleA = () => import('./largeModuleA'); // Dynamic import
const loadLargeModuleB = () => import('./largeModuleB');
// ... use them when needed, e.g., on button click
```

## 3. Essential Plugins

Use these plugins for robust and optimized builds.

### A. `HtmlWebpackPlugin`

Always generate your `index.html` and inject bundles automatically.

❌ BAD: Manually updating `<script>` tags in `index.html`.
```html
<!-- index.html -->
<script src="./dist/main.bundle.js"></script>
```

✅ GOOD: Let `HtmlWebpackPlugin` handle it.
```javascript
// webpack.common.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  plugins: [
    new HtmlWebpackPlugin({
      template: './public/index.html', // Your template HTML
      title: 'My App',
    }),
  ],
  // ...
};
```

### B. `DefinePlugin`

Inject environment variables safely and enable dead-code elimination. `mode` handles `process.env.NODE_ENV` automatically. For custom variables, use `DefinePlugin`.

❌ BAD: Hardcoding API keys or relying on client-side `process.env`.
```javascript
// src/api.js
const API_URL = 'https://dev.api.example.com'; // Changes for prod
```

✅ GOOD: Injecting via `DefinePlugin`.
```javascript
// webpack.common.js
const webpack = require('webpack');
module.exports = {
  plugins: [
    new webpack.DefinePlugin({
      'process.env.API_URL': JSON.stringify(process.env.API_URL || 'http://localhost:3000/api'),
    }),
  ],
  // ...
};

// src/api.js
const API_URL = process.env.API_URL; // Injected at build time
```

## 4. Modern Tooling & Maintenance

Stay current with webpack and Node.js versions.

### A. Keep Dependencies Updated

Regularly update `webpack`, `webpack-cli`, `webpack-dev-server`, and Node.js for performance gains and security fixes.

### B. `output.clean`

Always use `output.clean: true` to prevent stale files in your `dist` directory.

❌ BAD: Manually deleting `dist` or having old files linger.
```javascript
// package.json
"scripts": {
  "build": "rm -rf dist && webpack --config webpack.prod.js"
}
```

✅ GOOD: Built-in `clean` option.
```javascript
// webpack.common.js
module.exports = {
  output: {
    clean: true, // Automatically cleans the output directory before emit
    // ...
  },
  // ...
};
```

© sanjeed5 · CC0-1.0 · sanjeed5/awesome-cursor-rules-mdc

Similar IDE rules

All IDE rules for Frontend and UI →

From the same set240

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor