The Shopware 6.5 storefront ships with almost 500Kb of JavaScript. And this is due to a large set of JS plugins of which some might not be needed in your shop. What about removing some of it? Here is a neat Webpack trick that allows you to do just that.
Shopware 6.5 already got rid of jQuery
With the Shopware 6.5 release, the good news was already that the JavaScript bundle became a lot less: jQuery was removed (and the Bootstrap scripts no longer rely on it). And in my own personal benchmarks this shaved about 200Kb off the bundle. This is definitely good.
But we can always do better. There are still a lot of JavaScript plugins loaded into the bundle, which bring in again other NPM packages. And some of them might not be needed, especially when you start adding your own stuff. For instance, what if you want to rewrite the add-to-cart behaviour or use another product slider?
The window.PluginManager
is not good enough
The first option is that you simply write your own plugin (extending upon the Plugin
class of Shopware) and use the PluginManager.override()
method to override the original JavaScript plugin. Yet another approach is to simply register your own plugin with PluginManager.register()
and remove the old JS plugin with PluginManager.deregister()
.
While this does something good for the plugins in runtime, it does not effect the bundle size. The original JS plugin is still imported (with all of its own imports) and tree-shaking is not powerful enough to know that an unregistered JS plugin should be excluded from the bundle.
Instead, if you want to remove something from the bundle, you will need to apply Webpack magic.
Let the magic happen
In a plugin, you can add a Resources/app/storefront/build/webpack.config.js
that is automatically picked up by the global Webpack process. In this plugin configuration, you can extend the global Webpack configuration object. A common trick is here to play around with resolve
aliases, to allow an additional NPM package to be installed via the plugin.
However, we can also do other things with resolvers. This would either involve a custom Webpack resolving plugin (been there, done that, not the easiest thing to do) or reuse existing Webpack plugins that help do the job.
For instance, there is the IgnorePlugin
that allows you to remove (or ignore) specific imports.
Ignoring a JS plugin? Nope.
In the main.js
file of the Storefront
bundle, there is an import for the AddToCart
plugin:
import AddToCartPlugin from './plugin/add-to-cart/add-to-cart.plugin';
With the IgnorePlugin
plugin, you could remove this source alltogether, by adding the following Webpack configuration:
const path = require('path');
const webpack = require('webpack');
module.exports = () => {
return {
plugins: [
new webpack.IgnorePlugin({ resourceRegExp: /src\/plugin\/add-to-cart\/add-to-cart.plugin/ })
],
}
}
Pretty cool. But with one side-effect. With this configuration, the import of add-to-cart.plugin.js
will simply result in null
. So the value of the AddToCartPlugin
variable in the main.js
file of the Storefront
bundle would be null
too. And further along, the PluginManager
is called to register the AddToCart
plugin, which fails because it did not expect a null
value as plugin. Removing the source is a bit too dramatic.
Replacing the plugin
Meet the NormalModuleReplacementPlugin
plugin. It replaces imports, instead of ignoring them. For instance, I might replace the original add-to-cart.plugin.js
file with a custom version by using the following Webpack configuration:
const path = require('path');
const webpack = require('webpack');
module.exports = () => {
return {
plugins: [
new webpack.NormalModuleReplacementPlugin(
/src\/plugin\/add-to-cart\/add-to-cart.plugin/,
path.resolve(__dirname + '/../src/plugin/fake-add-to-cart')
)
],
}
}
Next, create a file src/plugin/fake-add-to-cart.js
in your own plugin:
import Plugin from 'src/plugin-system/plugin.class';
export default class FakePlugin extends Plugin {}
And now the original plugin (which might include lots of other dependencies) is never called anymore, but replaced with a very downsized version of your own. (Note that the class name in our custom plugin actually has no effect.)
Small note on Webpack
If you are using this Webpack configuration in your own plugin, note that it imports webpack
(which is probably not globally available). Just to make this work, make sure to install Webpack within your plugin with the following command: npm install webpack:^5.75
.
About the author
Jisse Reitsma is the founder of Yireo, extension developer, developer trainer and 3x Magento Master. His passion is for technology and open source. And he loves talking as well.