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.
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.