I'm slowly diving into the world of Vue Storefront - having given quite a few developer trainings on the topic already and also preparing myself for a few projects (and extensions). One of the key things that people still find lacking is theme inheritance - the ability to extend a child theme from a parent theme. And while one of the VSF core developers hinted that extending the Webpack configuration with a plugin like NormalModuleReplacementPlugin should be possible, nobody seemed to come up with the solution yet. So here it is: Theme inheritance for Vue Storefront.

TL;DR

Bottom-line is this Webpack configuration that you can add to your own webpack.config.js file in your own theme folder (for example src/themes/yireo):


const webpack = require("webpack");
const path = require("path");
const fs = require("fs");
const PARENT_THEME = 'default'
module.exports = function (config) {
  config.default.plugins.push(
    new webpack.NormalModuleReplacementPlugin(/(\.*)/, resource => {
      let match = resource.request.match(/^theme\/(.*)/);
      if (match) {
        if (!fs.existsSync(path.resolve(__dirname, match[1]))) {
          resource.request = resource.request.replace(
            /^theme\//,
            'src/themes/' + PARENT_THEME + '/'
          );
        }
      }
    })
  );
  return config;
};

The Webpack configuration is extended by using the NormalModuleReplacementPlugin plugin, which takes a resource that needs to be resolved by Webpack (resolving means: finding the file in your project to serve to the Webpack bundler) and then translates it into the relevant file: The fs.existsSync() call detects whether the current file is found in the current child theme. And if not, it falls back to the parent theme identified by PARENT_THEME.

What works, what does not

As a proof of concept I've been overriding the homepage (pages/Home.vue) by simply copying the file from the original default theme (src/themes/default/pages/Home.vue) to my own theme. This works nicely. Other files should be imported using the prefix theme/ which dynamically resolves into the current theme. However, once a file would be included using an absolute or relative path (../components for example), the trick no longer works: You will need to copy more files than you want.

While the theme inheritance works nicely for components (*.vue) and few other files (*.js), it does not work for everything. By testing things step-by-step, I found the following files to be still needed within your theme folder src/themes/xyz:

  • Assets (static files like images, JSON-files, fonts and more) contained in the folder assets. All of these files seem to be picked up by absolute paths.
  • CSS / SCSS in the css folder.
  • Language files in the resources/i18n folder.
  • The main index.js file of your theme.

Step-by-step guide

So let's go through this step-by-step. Create a new folder src/themes/yireo (because obviously any theme that you are going to create is going to be named after me, as a thank-you-note).

Next, copy the assets and css files to it. Practically, there is a lot to change in this little step. You could keep the css/main.scss file and throw away the rest. And likewise, assets are only needed if you refer to them. But that's a bit out of scope for this blog.

Next, create the webpack.config.js file with the code mentioned above. The only thing left to do is to generate your own index.js file. Or, theoretically, if you don't want to make any changes in that file, you could also simply just add the following and be done with it:


export { themeEntry, initTheme } from "../default/index";

Last but not least, point the theme variable in your config/local.json file to the new theme yireo. Restart your Node process (yarn dev) and you should be good to go.

Posted on November 19, 2019

About the author

Author Jisse Reitsma

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.

Sponsor Yireo

Looking for a training in-house?

Let's get to it!

We schrijven niet te commerciële dingen, we richten ons op de technologie (waar we dol op zijn) en we komen regelmatig met innovatieve oplossingen. Via onze nieuwsbrief kun je op de hoogte blijven van al deze coolness. Inschrijven kost maar een paar seconden.

Do not miss out on what we say

This will be the most interesting spam you have ever read

We schrijven niet te commerciële dingen, we richten ons op de technologie (waar we dol op zijn) en we komen regelmatig met innovatieve oplossingen. Via onze nieuwsbrief kun je op de hoogte blijven van al deze coolness. Inschrijven kost maar een paar seconden.