Verified on Shopware 6.7

Webpack in Shopware 6

While Shopware is moving toward Vite, many production shops still run on Webpack for their storefront builds. Whether you're maintaining an existing shop or can't migrate to Vite yet, here's how to customize the Webpack configuration effectively.

How Shopware Loads Webpack Config

Shopware's build system looks for a webpack.config.js in your plugin's storefront build directory:

YourPlugin/
└── src/
    └── Resources/
        └── app/
            └── storefront/
                ├── build/
                │   └── webpack.config.js    ← Your overrides go here
                └── src/
                    └── main.js

The config file exports a function that receives the base webpack config and returns the modified version:

// webpack.config.js
module.exports = function (webpackConfig) {
    // Modify webpackConfig here
    return webpackConfig;
};

1. Adding Custom Loaders

Need to process a file type that Shopware doesn't handle by default? Add a loader:

module.exports = function (webpackConfig) {
    // Add SVG inline loader for custom icon system
    webpackConfig.module.rules.push({
        test: /\.svg$/,
        include: /icons/,
        use: [
            {
                loader: 'raw-loader',
            },
        ],
    });

    return webpackConfig;
};

Install the loader in your plugin:

cd custom/plugins/YourPlugin/src/Resources/app/storefront/
npm install raw-loader -save-dev

2. SCSS Variable Injection

Override Shopware's SCSS variables globally without duplicating files:

const path = require('path');

module.exports = function (webpackConfig) {
    // Find the sass-loader rule and prepend custom variables
    const sassRule = webpackConfig.module.rules.find(
        rule => rule.test && rule.test.toString().includes('scss')
    );

    if (sassRule && sassRule.use) {
        const sassLoader = sassRule.use.find(
            use => use.loader && use.loader.includes('sass-loader')
        );

        if (sassLoader) {
            sassLoader.options = {
                ...sassLoader.options,
                additionalData: `
                    $sw-color-brand-primary: #5288c1;
                    $sw-color-brand-secondary: #1e2c3a;
                    $sw-border-radius: 8px;
                `,
            };
        }
    }

    return webpackConfig;
};

3. Bundle Analysis

See exactly what's making your storefront bundle large:

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = function (webpackConfig) {
    if (process.env.ANALYZE) {
        webpackConfig.plugins.push(
            new BundleAnalyzerPlugin({
                analyzerMode: 'static',
                reportFilename: 'bundle-report.html',
                openAnalyzer: false,
            })
        );
    }

    return webpackConfig;
};

Run with:

ANALYZE=true bin/build-storefront.sh
# Open bundle-report.html in your browser

4. Tree-Shaking Fixes

Sometimes Webpack includes entire libraries when you only need one function:

module.exports = function (webpackConfig) {
    // Ensure tree-shaking works properly
    webpackConfig.optimization = {
        ...webpackConfig.optimization,
        usedExports: true,
        sideEffects: true,
    };

    // Replace heavy imports with lighter alternatives
    webpackConfig.resolve.alias = {
        ...webpackConfig.resolve.alias,
        // Use lodash-es instead of lodash for tree-shaking
        'lodash': 'lodash-es',
    };

    return webpackConfig;
};

Also check your imports:

// Bad - imports entire library
import _ from 'lodash';
_.debounce(fn, 300);

// Good - imports only what's needed
import debounce from 'lodash-es/debounce';
debounce(fn, 300);

5. Multi-Theme Builds

If you run multiple sales channels with different themes:

const path = require('path');

module.exports = function (webpackConfig) {
    // Add theme-specific entry points
    webpackConfig.entry = {
        ...webpackConfig.entry,
        'theme-b2b': path.resolve(__dirname, '../src/themes/b2b/main.js'),
        'theme-b2c': path.resolve(__dirname, '../src/themes/b2c/main.js'),
    };

    return webpackConfig;
};

Each entry gets its own bundle, loaded based on the active sales channel theme.

6. Source Maps for Production Debugging

When you need to debug production issues without exposing source code:

module.exports = function (webpackConfig) {
    if (webpackConfig.mode === 'production') {
        // Hidden source maps - uploaded to error tracking, not served to users
        webpackConfig.devtool = 'hidden-source-map';
    }

    return webpackConfig;
};

Upload the generated .map files to your error tracking service (Sentry, Bugsnag) and delete them from the public directory.

Common Debugging Commands

# Build with verbose output
bin/build-storefront.sh -verbose

# Build specific plugin only (faster during development)
bin/build-storefront.sh -only YourPlugin

# Watch mode for development
bin/watch-storefront.sh

Gotchas

  1. Don't replace the entire config - always modify and return the existing webpackConfig
  2. Plugin load order affects merge order - last plugin to modify a config key wins
  3. Clear cache after config changes - bin/console cache:clear and delete var/cache/
  4. Node version matters - check .nvmrc in Shopware root for the expected version
  5. Production vs dev - always test with bin/build-storefront.sh (production mode), not just watch mode

Need help optimizing your Shopware storefront build? Talk to us.