Don Udugala

PHP Programmer

Full Stack Developer/Magento Developer

Web Solution Architect

Photographer

Love Python, Node, React

0

No products in the cart.

Don Udugala

PHP Programmer

Full Stack Developer/Magento Developer

Web Solution Architect

Photographer

Love Python, Node, React

Blog Post

PWA Studio Override Modules using Webpack compiler path mapping

July 16, 2022 E-Commerce, Magento, PWA Studio
PWA Studio Override Modules using Webpack compiler path mapping

Last time I explained how to override PWA Studio modules using Official PWA Studio documentation.

Checkout my last video to find out another method to override modules.

You can find the original article about the webpack override plugin from here.

First let’s create a plugins folder in ./src and create moduleOverrideWebPack.js file and call it in the local-intercept.js

local-intercept.js

const moduleOverridePlugin = require('./src/plugins/moduleOverrideWebPack');

function localIntercept(targets) {
const componentOverrideMapping = {
'@magento/venia-ui/lib/components/Footer/footer.js': './src/components/Footer/footer.js',
'@magento/venia-ui/lib/components/Header/header.js': './src/components/Header/header.js',
'@magento/venia-ui/lib/components/Header/header.js': './src/components/Header/header.js',
'@magento/peregrine/lib/talons/MegaMenu/useMegaMenu.js': './src/lib/talons/MegaMenu/useMegaMenu.js',
};

targets.of('@magento/pwa-buildpack').transformUpward.tap(def => {
def.staticFromRoot.inline.body.file.template.inline =
'./public/{{ filename }}';
});

targets.of('@magento/pwa-buildpack').webpackCompiler.tap(compiler => {
new moduleOverridePlugin(componentOverrideMapping).apply(compiler);
});
}

module.exports = (targets) = localIntercept;

in local-intercept.js we are calling pwa-buildpack webpackCompiler hook.

You can find out more about webpack compiler hooks in webpack compiler-hooks document.

moduleOverrideWebPack plugin will map old path with new modified files.

moduleOverrideWebPack.js

const path = require('path');
const glob = require('glob');

module.exports = class NormalModuleOverridePlugin {
constructor(moduleOverrideMap) {
this.name = 'NormalModuleOverridePlugin';
this.moduleOverrideMap = moduleOverrideMap;
}

requireResolveIfCan(id, options = undefined) {
try {
return require.resolve(id, options);
} catch (e) {
return undefined;
}
}
resolveModulePath(context, request) {
const filePathWithoutExtension = path.resolve(context, request);
const files = glob.sync(`${filePathWithoutExtension}@(|.*)`);
if (files.length === 0) {
throw new Error(`There is no file '${filePathWithoutExtension}'`);
}
if (files.length > 1) {
throw new Error(
`There is more than one file '${filePathWithoutExtension}'`
);
}

return require.resolve(files[0]);
}

resolveModuleOverrideMap(context, map) {
return Object.keys(map).reduce(
(result, x) => ({
...result,
[require.resolve(x)]:
this.requireResolveIfCan(map[x]) ||
this.resolveModulePath(context, map[x]),
}),
{}
);
}

apply(compiler) {
if (Object.keys(this.moduleOverrideMap).length === 0) {
return;
}

const moduleMap = this.resolveModuleOverrideMap(
compiler.context,
this.moduleOverrideMap
);

compiler.hooks.normalModuleFactory.tap(this.name, (nmf) => {
nmf.hooks.beforeResolve.tap(this.name, (resolve) => {
if (!resolve) {
return;
}

const moduleToReplace = this.requireResolveIfCan(resolve.request, {
paths: [resolve.context],
});
if (moduleToReplace && moduleMap[moduleToReplace]) {
resolve.request = moduleMap[moduleToReplace];
}

return resolve;
});
});
}
};
To map override file simply add original file location string and map the newly created file insideĀ componentOverrideMapping object.
const componentOverrideMapping = {
    '@magento/venia-ui/lib/components/Footer/footer.js': './src/components/Footer/footer.js',
    '@magento/venia-ui/lib/components/Header/header.js': './src/components/Header/header.js',
    '@magento/venia-ui/lib/components/Header/header.js': './src/components/Header/header.js',
    '@magento/peregrine/lib/talons/MegaMenu/useMegaMenu.js': './src/lib/talons/MegaMenu/useMegaMenu.js',
};

Next make sure you will modify the path of the imports inside the new file.

For example in my src/components/Footer/footer.js, I have changed the path to footer.module.css since we don’t have footer.module.css file in our new Footer directory.

import defaultClasses from '@magento/venia-ui/lib/components/Footer/footer.module.css';

I have add the link to code base in github and youtube video explaining the process below.

To access code base :
github.com/theiconnz/pwastudio-override