From Gulp to Heft: Webpack Config in SPFx 1.22+

- Updated:

You followed the Microsoft instructions to upgrade from Gulp to Heft. During this upgrade, you found some Webpack configuration that also needs to be migrated. It is a single configuration required only for this project. Let me explain what you can do and when to do it.

TL;DR: SPFx Webpack Customization Approaches

There are actually three ways to modify the Webpack configuration.

  • Heft Webpack Patches – Reusable npm packages, complex plugins (bundle analyzer, external tools)
  • spfx-customize-webpack.js – Project-specific config, easy migration from Gulp, standard Webpack rules
  • webpack-eject: Full control, custom build pipeline, advanced scenarios (breaks SPFx updates)

I looked just at the first two options since the last one has way higher complexity.

Option 1: Heft Webpack Patch in SPFx 1.22 and beyond

In my article about how to make WebAssembly work in the SharePoint Framework 1.22 and beyond, I used this approach.

The main purpose of webpack patches is for reusability. As noted in the documentation, the Webpack bundle analyzer is a great example of this.

You create an npm package first.

Screenshot of the packagejson for the gulp to heft migration
The package Json of the reusable webpack heft patch

You create a file that tells Webpack how to customise.

Screenshot of webpack bundle analyser integration
The code that makes the bundle analyzer run in sharepoint framework

Once you publish this package, you have a perfect reusable Webpack configuration for all of your projects.

The last step is to reference the package in the webpack-patch.json configuration in the config folder.

{
  "$schema": "https://developer.microsoft.com/en-us/json-schemas/spfx-build/webpack-patch.schema.json",
  "patchFiles": [
    "./node_modules/heft-patch/src/heft-wp-bundle-analyser.js"
  ]
}

And with that, you have a perfectly fine reusable package just for these configurations.

Option 2: Project-Specific Webpack configuration

Another option for the Gulp to Heft migration is to have a project specific configuration. In most projects and cases, you might have an on-off configuration you like to apply specifically for your project. WebAssembly is a great example of that. I might need it in my current project, but nowhere else.

For such configurations, all that is needed is to create a spfx-customize-webpack.js file in the configuration directory. The Heft build chain looks up this by default if such a file exists and includes its contents in the webpack configuration.

/**
 * SPFx Webpack Customization - WebAssembly Support
 * Automatically discovered by @microsoft/spfx-heft-plugins
 */
module.exports = function(webpackConfig, taskSession, heftConfiguration, webpack) {
  webpackConfig.module.rules.push({
    test: /\.wasm$/,
    type: 'webassembly/async',
  });

  webpackConfig.experiments = {
    asyncWebAssembly: true,
  }
};

Compared to the original gulp file, it almost looks identical.

'use strict';
const build = require('@microsoft/sp-build-web');

// WebAssembly configuration
build.configureWebpack.mergeConfig({
  additionalConfiguration: (generatedConfiguration) => {
    generatedConfiguration.module.rules.push({
      test: /\.wasm$/,
      type: 'webassembly/async',
    });
    generatedConfiguration.experiments = {
      asyncWebAssembly: true,
    }
    return generatedConfiguration;
  }
});

build.initialize(require('gulp'));

Key Differences: SPFx Webpack Configuration Migration (Gulp → Heft)

Gulp used this in the gulpfile.js:

// gulpfile.js (root level)
build.configureWebpack.mergeConfig({
  // configuration here
});

In Heft, you have to use the following:

// config/spfx-customize-webpack.js (dedicated file)
module.exports = function(webpackConfig, taskSession, heftConfiguration, webpack) {
  // configuration here
};

API Pattern Pattern & Function Signatures

Of course, with a new build chain, the API has slightly changed.

The Gulp approach used the following to merge the configuration.

build.configureWebpack.mergeConfig({
  additionalConfiguration: (generatedConfiguration) => {
    // Modify generatedConfiguration
    return generatedConfiguration;
  }
});

In Heft, you can modify the Webpack configuration directly without ejecting.

module.exports = function(webpackConfig, taskSession, heftConfiguration, webpack) {
  // Modify webpackConfig directly
  // No return needed
};

Key improvements

To apply the configuration change this way comes with many great benefits. It uses autodiscovery and simply removing this file will bring SharePoint Framework back to its original state. This is true for the Webpack Patch, too, of course. Other benefits include a simpler API that allows direct modification of the configuration, rather than the callback pattern, and provides better context.

This approach is an easier, more applicable way for many developers, and the most straightforward way to migrate from Gulp to Heft. I will make the transition smoother and less stressful.

Summary

As you can see in the screenshot, both scenarios work well together in a single solution.

Screenshot of both options working in harmony together
Both options are complementary to each other and work well together

The second option works because it is part of the @rustack/heft-webpack5-plugin. It is the foundation for @microsoft/spfx-heft-plugins, which provides the auto-discovery functionality of spfx-customize-webpack.js.

Webpack patches are ideal for reusable configurations, while the second option is better for simple, one-off tweaks.

As I mentioned in my previous blog post, where I upgrade SPFx using AI, documentation for the new Heft toolchain, especially for SPFx, still has room to improve. Clearer guidance on when to choose each approach would help you feel more confident and supported in your migration decisions.

The option I showed with ‘spfx-customize-webpack.js’ has been completely forgotten to document.

I tested it on a real project that I upgraded to 1.22.1, and it works perfectly.

In one of the upcoming blog posts, I will cover how to apply multiple webpack patches in a single package.

Further readings

Find more posts in the following categories

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.