Progressive web applications are growing in popularity by the month, particularly in eCommerce. More and more online retail businesses are opting for PWA storefront development on Magento (Adobe Commerce). This modern web technology turns an eCommerce store into a user-friendly web app with an app-like experience, giving you more chances to make prospects happy and encourage them to buy.
In this blog article, we’ll introduce you to everything you should know about building a PWA with the use of the PWA Studio tools. We’ll explore the pros and cons of using the Magento 2 PWA Studio and explain what to keep in mind when working on a Magento PWA studio project. Then, we’ll walk you through the steps for building the progressive web app with code examples and detailed instructions. As a final touch, we’ll share handy suggestions from the pros to learn more about setting up your Magento PWA Studio.
Table of Content
What to Expect From This Magento PWA Studio Guide
A Quick Introduction to Progressive Web Apps
websites are becoming a real hit. The number of users who shop from their mobile phones is continuously increasing, contributing to the growth of mobile commerce. In essence, progressive web apps are not actually applications that we’re used to in the conventional sense. It’s a very modern, fast, and highly-optimized mobile version of a website.
And progressive web apps, undoubtedly, have many benefits over good-old native applications; here are some of them:
- PWAs are fast and efficient;
- They function in web browsers like Chrome, Safari, and Opera and are accessible from search engines;
- They don’t have to be downloaded to the device from Google Play or the AppStore;
- They practically take up zero storage space on the user’s device;
- They have the same impeccable UX and UI as native apps and are very simple to navigate;
- They support the offline mode due to caching static files;
- And generally, less in terms of web development (at least if compared to native apps. You have to build native apps up as at least two different versions in terms of coding languages to fit the standards of iOS and Android, to provide an example).
In a nutshell, this, to a great extent, explains the current high demand for progressive web apps in the sphere of eCommerce and online sales. Put simply, everything used in the PWA leads to a boost in how convenient the
is for users.In turn, this helps lower the bounce rate, enhance the conversion rate, and result in revenue growth. So, a growing number of online store owners wish to invest in their own progressive web apps.
One of the reasons for getting a PWA storefront project lies in the architectural transformation the store undergoes. Known as
, this concept involves separating the frontend from the backend and moving from mere server-side rendering to the client-side one from the second visit. It provides various benefits to store owners, like faster page loading and the ability to add more fronts to a single codebase.So opting for headless commerce in the form of first getting a PWA storefront now is also a step helping merchants prepare their architecture for the future. As new devices become available for shopping, the UI/UX requirements may be different due to users' various behaviors and device peculiarities. Additionally, implementing
can further enhance performance, ensuring faster load times and smoother user experiences.But what do you have to understand about the PWA development process?
The Approaches to PWA Development
Let’s begin by making it clear that there are multiple
on Magento. Just as in the case of the construction of buildings, PWA developers can opt for several different paths to reach more or less the same result:- via custom coding using a progressive frameworks (just plain React.js, Angular.js, or Vue.js);
- Building the progressive web app by customizing a ready-made PWA theme (these are the PWA Studio that’s officially brought by Magento, or other third-party themes like the Scandi PWA toolkit or the Vue Storefront, to give a couple of examples);
- Opting for a combination of custom coding and theme customization (this supposes a blend of the two points above).
If you are planning to create a highly customized Magento PWA storefront, you can't rely on the developer tools provided by the PWA theme only. Plain ReactJS coding would be the best option here. If your dev team doesn't have a good command of React, turn to our
, who are clearly aware of how the PWA technology functions.What This Magento PWA Studio Tutorial Focuses On
Now that this is clear, we’d like to point out that this blog post is devoted to progressive web apps created with the help of the Magento PWA Studio.
For this specific case, we’ll operate from the idea that your Magento online store functions on Magento 2 (either open source or hosted) that’ll be fitted with a PWA. Whether you've migrated from M1 or created the website on M2 from the beginning, you'll find this guide helpful if you’d like to opt for a
solution and get a Magento PWA storefront.In this blog article, we’ll cover the following things:
- Give an introduction to the Magento PWA Studio tools, as well as the main strengths and weaknesses of their use.
- Go over the UX and UI peculiarities that have to be taken into account when creating a progressive web app.
- Provide step-by-step instructions in the Magento 2 PWA Studio tutorial block. We’ll be creating a homepage of a PWA storefront using Magento PWA Studio's tools (providing examples of code).
- Bring up some points regarding the work with the Magento backend if you build the web app via the Magento 2 PWA Studio.
- Lastly, we’ll share recommendations on launching the Magento PWA Studio project, as well as which errors you can bypass when working with the PWA Studio.
Let’s get started!
1. What Is Magento PWA Studio?
As was briefly mentioned a bit earlier, the Magento 2 PWA Studio is a toolkit. It was designed by the official Magento team specifically to help developers build progressive web applications on the Magento 2 platform. The tool comprises ready-to-use, out-of-the-box PWA solutions that can come in handy during web development. Plus, it eliminates the possibility of code conflicts and allows a PWA to run without a hitch, thanks to its built-in consistency with the Magento coding standard.
Yet if everything’s available out of the box, why do developers even bother to code everything (or partially) from scratch? Well, to be fair, the Magento PWA Studio has its own benefits and weaknesses. Below, we’ll tell you more about them.
Advantages of Using the Magento PWA Studio
1. The Magento PWA Studio is not monolithic
This surely is a beneficial thing that simply means that the available solutions of the Adobe PWA Studio for Magento are flexible and can be used partially. You won’t need to resort to the entire code in an obligatory manner. For instance, you can make use of just some of its parts, such as Peregrin or the PWA Buildpack.
2. The app’s architecture and framework are out-of-the-box
This is a very crucial point worthy of note. The thing is that developers often end up atoning for their errors if they’ve made irrational choices when building the application’s architecture at an early app development stage. If something has illogical organization, and this pops up later in the development environment, a lot of time will be needed for the fixes.
Yet, it's not an issue with the Studio. When the architecture is available as a skeleton and has built-in consistency with the Magento coding standard, consider that this point is already safely taken care of. Thus, this is among the handiest Magento PWA Studio features that benefit the developers.
3. The application builder is already configured
Having the opportunity to save some development hours and time on handling the setups of the application builder is another bright side of the PWA Studio. Everything in the app builder is already configured for you to use.
4. The ready-made app elements are adaptable
The PWA Studio has quite an extensive range of ready-made site elements you can choose from and use during development. The greatest thing about them is that they can be used entirely as they are. Yet, if necessary, the elements can be modified and customized according to the needs (be they due to design or those changes required solely for app development).
5. Routing & caching can be used without being tweaked
The matters of routing and caching are also the PWA Studio's strong points. These solutions are provided so that there’s no need to tweak or modify them. Note that this applies to the case if you’re using the standard Magento-way routing in your PWA Studio project.
6. The service workers are already set up & out-of-the-box
The Service Worker is a commonly used browser resource caching tool on the Magento PWA. The Magento 2 PWA Studio has already taken care of the time-consuming setup work and is in its ready-to-run shape.
Downsides of Using the Magento PWA Studio
1. Code excessiveness
Because the Magento team did their best to develop more or less universally applicable solutions, this obviously resulted in lots of excessive code. This basically means that developers will need to invest their time in “cutting out” those parts that aren’t relevant to their development environment. Why is this step required? To say the least, excessive code negatively influences page loading.
2. Code complexity due to abstractions
Ready-made Magento PWA Studio code solutions mean that their use often implies the reuse of unwanted abstractions or probable bugs. This also means that the code is, at times, complicated, inconvenient in some places, and, thus, takes time to figure out and untangle.
That said, keeping in mind particular specifics of the Magento store that you're building, many solutions by the Magento 2 PWA Studio can be unnecessary for your case. For instance, if your web application doesn't need a product cart, the provided functionality will be out of place. This will lead you to cut out the code and contexts that don't fit your PWA storefront project.
3. Lots of time for studying the ready-made code
When provided with an out-of-the-box solution, in the app development case, you should be looking a gift horse in the mouth. Developers make every effort to take their time and study the existing code before they get their hands on creating their own. Primarily, this is done so as not to end up reinventing the wheel (writing code for something that already exists).
40 Hours of Magento Services. FOR FREE
Try our custom development, optimization, support, and design services. One week, free of charge, no strings attached.
2. Creating Ultimate UX/UI for a Flawless Magento 2 PWA
Because progressive web application has to offer amazing navigation, it’s quite self-explanatory that the app’s UX and UI have to be given much consideration.
To say the least, if you’re migrating a website to Magento 2, your old design is a no-go. And even if you have worked on optimizing your mobile design, it’ll still most likely need some additional improvement because of the high UX/UI standards for PWA creation.
To give you a few examples of the trends designers tend to follow lately, it has become customary to place crucial page elements closer to the bottom of the screen. Such elements can include buttons, site menus, drop-down lists, pop-ups, etc.
This is done to make all the major “touchpoints” thumb-reachable. Especially, if you keep in mind that the screen sizes of mobile devices are getting bigger, meaning that element placement at the top of the screen will require “unnatural” movements. Feel free to browse these
for some inspiration.Thus, just shrinking the desktop version to fit mobile devices is, by all means, not enough. Accessibility and reachability are some of the key points to note when working on Magento 2 PWA designs. Below we’ll list more principles that are best to follow.
Must-Follow UX/UI Principles
It’s not just about what your PWA will look like on a mobile screen. It’s all about how it will behave and how user-friendly and easy it will be to use. These are the 10 main rules not to forget about when creating prototypes for the future Magento 2 PWA:
- Achieving the shortest possible page load times should be among the top goals.
- Dedicate a separate pop-up or screen for a new action on the page.
- Site navigation and any move should be easy for the user.
- Try to stick to simpler and more basic fonts and visual components.
- Those parts of the page that can be tapped on should be highlighted for visual help.
- Major elements that can be clicked on should be positioned in the lower part of the screen.
- Remember that some devices can, by default, take up half of the screen if the user opens their keyboard.
- Fall back on universally-applicable UX/UI “rules” that regard different sizes of screens.
- Don’t forget about how the pages will differ if used offline.
- Ideally, data should be refreshed without a full page reload.
UX/UI for a PWA on Examples
In order to not multiply words, we’ve decided to provide you with some visually understandable examples. We’ve overviewed the mobile versions of several page types of various websites. For each of them, we have prepared our own prototypes. They portray how the current design could be improved if the site owners would request a Magento 2 PWA storefront. To make things clear, we’ve explained each of our UX/UI choices that you can see in the comments below the prototypes. We also have a dedicated article with
, showing how other companies leverage PWAs for a better online experience.a) Homepage - House of Fraser
Let’s start by taking a closer look at the homepage example. We’ve chosen the one on the
. In the table below, we present you with the whole original design and the full prototype that you can scroll through.How the current mobile design looks like (full screenshot) | Our full prototype for the PWA mobile design |
Below, we’ve broken down the designs into pieces and will share our ideas on what should be changed and why.
How the current mobile design looks like | Our prototype for the mobile design of the PWA |
- When we’re taking a homepage into consideration, it’s important to let the shoppers know that the application is available for download at the very top of the page. This is why we’ve moved the rounded elements with Google Play and App Store logos all the way from the bottom of the page (where they’re located on the original design).
- Plus, we removed the unnecessary first stripe that duplicates the special offer (“70% off reduction”) since it’s described in the main banner. On a side note, it makes sense to display this specific stripe at the top of other page types, such as Categories, to serve as a reminder.
- What’s for the second stripe (with the “£10 voucher”), we’ve decided to leave it as it is on the homepage yet added the “Close” button. Such advertisement stripes and larger banners are often very distracting, especially if presented in GIF format. Thus, there should be an opportunity to close them.
- The main banner with the “Sale” categories was extended into more than one scroll on the initial design. Yet, it doesn't comply with the mobile application approach. Its main idea lies in the fact that one screen should fit a single section without needing to scroll down. With that in mind, we’ve narrowed the block down with the “Sale” categories to just one screen.
How the current mobile design looks like (full screenshot) | Our full prototype for the PWA mobile design |
- This homepage design has product categories lined out one by one. This doesn’t make too much sense, so we’ve reassembled them into smaller category blocks.
- For the same reasons, we’ve reorganized the items presented in the “Don’t Miss” section into a slider format.
How the current mobile design looks like | Our prototype for the mobile design of the PWA |
- On a similar note, the current mobile design has an inexplicit swiper design of the “Top Sale Picks”. As you can notice, it seems as though there’s just one item. By making the second top-pick product “peek” on the right side, we made the slider more apparent.
- Last but not least, the “Stay in the Know” section for email sign-up has a strange “Men/Women” choice solution. We’ve decided to use a checkbox to make it not look like buttons with links that can lead you to some other page.
b) Category Page - Costco
The category page example we’d like to cover in our overview is the
. In the first table that follows, you can find the whole version of the prototype and the original design.How the current mobile design looks like (full screenshot) | Our full prototype for the PWA mobile design |
- As you can see, the header area is very large in the original layout. We’ve decided to minimize many areas, for example, the stripe with the COVID text that takes up too much space. Likewise, we moved the “Set Delivery ZIP Code” to the section by the filter and sorting.
- Because the ongoing design doesn’t allow changing the layout from a listing to a grid, we’ve added this point for navigation convenience.
- The “Member Only Item” block solution is also quite crude. For starters, we added the “Special Event” label atop the picture and the star rating, too. Furthermore, instead of having a field that states that “More colors are available”, we added more useful functionality that actually shows the color variations, materials, and sizes that a product can come in. Importantly, since the price isn’t visible on such items, we’ve made it more obvious that you have to sign in to see the item price.
- The wish list icon that’s used on the category is irregular. It looks like a bulleted list with a tiny “plus” sign in the top corner. We decided to change how it looked and moved the wish list functionality to the product page altogether.
- For convenience, we added the feature for autoloading products as the user scrolls the category and an indicator for the page number.
- Mentioning the “Related Categories” section, we believe that this block isn’t that necessary here as all the categories are readily available on the menu.
How the current mobile design looks like | Our prototype for the mobile design of the PWA |
- is also worth changing. In the original design, the filter doesn’t open to the full scale of the page. We expanded it to the full screen so that all options are easier to tweak. We also changed the way the price range is indicated. We allowed manual input or moving around the price range instead of selecting it as a checkbox. What is more, we now show the matching results at the bottom. Pressing the “Apply” button puts the filter in action and closes the filter section.
How the current mobile design looks like | Our prototype for the mobile design of the PWA |
- Lastly, the design of the “Sort by” element is a bit awkward. It takes up a full line and has an inconvenient drop-down. Our variant with a button that opens as a pop-up is much more user-friendly. This way, the options are easier to tap on, and when selected, the sorting is applied.
c) Product Page - Rebecca Atwood
Thirdly, what’s for our product page, we’d like to overview the
. Just as in the two previous examples, we show you the full version of the designs and then the broken-down pieces with our ideas on improving the Magento 2 PWA product page presentation.How the current mobile design looks like (full screenshot) | Our full prototype for the PWA mobile design |
Once again, below, we’ve broken down the designs and given comments.
How the current mobile design looks like | Our prototype for the mobile design of the PWA |
- The first point we decided to change was how the breadcrumb path was displayed, and we shortened it to one line.
- The size of the price digits is very small and needs to be enlarged. This is needed because how much an item costs is a very important point.
- The element for choosing the item’s size is located too low, although it’s more important than the product description text. We moved it up and got rid of the drop-down, using buttons for every separate variation instead.
- We also moved the “Quantity” element up and introduced the “+/-” for indicating the number of items. This is much simpler than using the keyboard for inputting the digit.
How the current mobile design looks like | Our prototype for the mobile design of the PWA |
- Characteristics and details located below the description don't take up much space, so there’s no need to hide them in pop-ups. We rearranged the layout of the text in a more readable way.
- The “Delivery Details” is a hardly visible element. The color is not the best choice. We placed it into a visible section showing the details in a pop-up.
How the current mobile design looks like (full screenshot) | Our full prototype for the PWA mobile design |
- The original design is missing product reviews. We believe that even if there isn’t any feedback on the item yet, it’s crucial to have this section to encourage users to add reviews.
- The “Related” products are placed quite inconveniently on the ongoing version of the page. A slider format can make such data look a lot more organized.
- Furthermore, we’ve decided to cut down the space the newsletter sign-up block took up.
- Lastly, we believe that the social media shortcuts belong in the footer area, so we moved them down. Similarly, we reworked the footer area a bit so it is consistent, simple to navigate, and to the point.
If you are stuck in the stage of creating UX prototypes for your future Magento 2 PWA storefront, our experienced
are ready to offer a helping hand. We know how to make an enhanced UX and give your mobile users a native-app-like experience. With this combo, you can increase your conversions and reduce acquisition costs.3. Building a PWA Using the Magento PWA Studio: Frontend Works
Now that the design part of the progressive web app is clearer, let’s move on to the section of this Magento 2 PWA Studio guide devoted to creating a PWA with the use of the PWA Studio's tools.
Objectives
Let’s begin by lining out what we’d like to accomplish. Our major goal is to build a Magento 2 PWA storefront with the help of the Magento PWA Studio toolkit. We’ll craft only the homepage and make the PWA theme more adapted for desktop and mobile storefronts. The reason is that the out-of-the-box theme is geared towards the mobile-first design. We plan to:
- Replace the standard out-of-the-box Venia storefront logo with our own.
- Add an expanded category menu (since in the Magento 2 PWA Studio, it comes in a format that’s tailored to mobile devices).
- Move the sign-in authentication into a pop-up.
Step 1: Getting Started
a) Configurations & setups preparation
We’ll run the web app on Ubuntu 18.04. Start by handling the required configurations on Ubuntu 18.04, install node JS and the needed auxiliary software.
sudo apt -y install curl dirmngr apt-transport-https lsb-release ca-certificates
curl -sL //deb.nodesource.com/setup_12.x | sudo -E bash -
sudo apt install nodejs
We also need the Yarn package manager. This Javascript package manager is noted for being a fast, safe, and trustworthy analog of NPM. It is capable of substituting the workflow that's currently used for the npm client, and it can support the current npm registry.
curl -sS //dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb //dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt update && sudo apt install yarn
b) Creating a new project
Now move on to the Magento 2 PWA Studio setup by creating a new project with the help of the PWA Studio Buildpack, as shown in the code below. Being one of the Magento PWA Studio essential packages, it offers the key build and development tools for your PWA storefront, including project setup tools, configuration management, and Magento extension frameworks.
One of the parts of the PWA Studio that's shown in the code example below is the Venia PWA storefront. It's an initial Magento PWA storefront, which is responsible for displaying components.mkdir venia-create-app && cd venia-create-appyarn create @magento/pwa.
After running the previous commands, you can move step by step and fill out all the values for the buildpack command. Alternatively, use the following code line to replace the variable values with your own.
buildpack create-project ./ --template "venia-concept" --name "pwa-studio-shop" --author "onilab" --backend-url "//master-7rqtwti-mfwmkrjfqvbjk.us-4.magentosite.cloud/" --braintree-token "sandbox_8yrzsvtm_s2bg8fs563crhqzk" --npm-client "yarn"
After installation, we get the following file structure:
c) Overriding inner components
For further development based on the Venia Concept by the Magento PWA Studio, we need a mechanism for replacing the internal components with our own. For this reason, we need:
- a Webpack plugin that will perform component substitution,
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;
});
});
}
};
- a file for mapping our components and those of the Magento PWA Studio,
module.exports = componentOverride = {};
- to add everything to the Webpack configuration file (webpack.config.js).
...
const moduleOverridePlugin = require('./moduleOverrideWebpackPlugin');
const componentOverrideMapping = require('./componentOverrideMapping');
...
module.exports = async env => {
...
clientConfig.plugins.push(
new moduleOverridePlugin(componentOverrideMapping)
);
...
};
d) Project folder
Create a folder that’ll contain our future components.
сd venia-create-app/src && mkdir components
As a result, we get the following web pages. Below you can take a look at what the Venia PWA storefront home page looks like after installation.
Step 2: Changing the PWA Logo
Now we’ll give you a detailed example of how to make changes to the
. To start, we’ll replace the logo.a) Copy the component folder completely
To make any changes, you need to copy the entire component to your folder. In the following example, we show how you can override an entire component via component override.
Copy the component from:
venia-create-app/node_modules/@magento/venia-ui/lib/components/Logo
To:
venia-create-app/src/components/Logo
b) Set up the override components
Carry out the setups in componentOverride. Here we add the override component for the module. Now instead of searching for the component the standard way, Magento will search for it in the way we've specified in this example:
module.exports = componentOverride = {
['@magento/venia-ui/lib/components/Logo']: 'src/components/Logo',
};
c) Replace relative paths with absolute ones
In order for our component to have the ability to use the Magento components, replace the relative paths with absolute paths, as shown in this example for the logo.
Change this part:
import { mergeClasses } from '../../classify';
import Image from '../Image';
import logo from './VeniaLogo.svg';
To look like this:
import { mergeClasses } from '@magento/venia-ui/lib/classify';
import Image from '@magento/venia-ui/lib/components/Image';
import logo from '@magento/venia-ui/lib/components/Logo/VeniaLogo.svg';
d) Change the logo
Remove the Venia storefront logo that the Magento 2 PWA Studio provides and upload your own logo instead, using your file.
import logo from './onilab-logo.svg';
Step 3: Rebuilding the Menu from Its Mobile Version to the Desktop Format
Moving on to a more complex example. By default, all menus (even the desktop menu) are hidden in the Venia PWA theme. So we need to reveal it.
a) Create a new component
Let's create a new component that will display categories. Follow the example below:
.root {
margin: 0 12rem
}
.link {
margin: 0 1.2em;
}
import React from 'react';
import {useCatalogContext} from "@magento/peregrine/lib/context/catalog";
import { Link } from '@magento/venia-drivers';
import classes from './topCategoryNav.css';
const TopCategoryNav = props => {
const [catalogState, { actions: catalogActions }] = useCatalogContext();
const { categories, rootCategoryId } = catalogState;
let topCategories = [];
Object.keys(categories).forEach(key => {
if (categories[key].parentId == rootCategoryId && categories[key].include_in_menu == 1) {
topCategories.push(categories[key]);
}
});
const navigation = topCategories.map(item => (
<Link key={item.id} className={classes.link} to={item.url_path.concat(item.url_suffix)}>
<span>{item.name}</span>
</Link>
));
return (
<div className={classes.root} >
{navigation}
</div>
);
}
b) Add the component to the menu
The next step is to add the component to the menu. To do this, replace and edit the header components.
Copy this file from:
venia-create-app/node_modules/@magento/venia-ui/lib/components/Header/header.js
To:
venia-create-app/src/copmponents/Header/header.js
c) Replace relative paths & swap the menu
Add the code that’ll allow you to hide the trigger of mobile navigation on the desktop version. Then add the code to display our new component on the output of menu categories.
import React, { Suspense } from 'react';
import { shape, string } from 'prop-types';
import Logo from '../Logo';
import { Link, resourceUrl, Route } from '@magento/venia-drivers';
// Modified by Onilab - Replace relative path with full path -- start
import AccountTrigger from '@magento/venia-ui/lib/components/Header/accountTrigger';
import CartTrigger from '@magento/venia-ui/lib/components/Header/cartTrigger';
import NavTrigger from '@magento/venia-ui/lib/components/Header/navTrigger';
import SearchTrigger from '@magento/venia-ui/lib/components/Header/searchTrigger';
import OnlineIndicator from '@magento/venia-ui/lib/components/Header/onlineIndicator';
import { useHeader } from '@magento/peregrine/lib/talons/Header/useHeader';
import { mergeClasses } from '@magento/venia-ui/lib/classify';
import defaultClasses from '@magento/venia-ui/lib/components/Header/header.css';
import PageLoadingIndicator from '@magento/venia-ui/lib/components/PageLoadingIndicator';
// Modified by Onilab -- end
//Added by Onilab - Import desktop menu component and useWindowSize from Peregrine to detect mobile -- start
import {useWindowSize} from "@magento/peregrine";
import TopCategoryNav from "../Menu/topCategoryNav";
//Added by Onilab -- end
// Modified by Onilab - Replace relative path with full path -- start
const SearchBar = React.lazy(() => import('@magento/venia-ui/lib/components/SearchBar'));
// Modified by Onilab -- end
const Header = props => {
const {
handleSearchTriggerClick,
hasBeenOffline,
isOnline,
searchOpen,
isPageLoading
} = useHeader();
const classes = mergeClasses(defaultClasses, props.classes);
const rootClass = searchOpen ? classes.open : classes.closed;
const searchBarFallback = (
<div className={classes.searchFallback}>
<div className={classes.input}>
<div className={classes.loader} />
</div>
</div>
);
const searchBar = searchOpen ? (
<Suspense fallback={searchBarFallback}>
<Route>
<SearchBar isOpen={searchOpen} />
</Route>
</Suspense>
) : null;
const pageLoadingIndicator = isPageLoading ? (
<PageLoadingIndicator />
) : null;
//Added by Onilab - Header elements depends on screen size -- start
const windowSize = useWindowSize();
const isMobile = windowSize.innerWidth <= 960;
const navTriggerMobile = isMobile ? (
<div className={classes.primaryActions}>
<NavTrigger />
</div>
) : null;
const categoryNavigation = !isMobile ? (
<TopCategoryNav />
) : null;
//Added by Onilab -- end
return (
<header className={rootClass}>
<div className={classes.toolbar}>
{/*Replaced by Onilab - Nav trigger obly on mobile-- start */}
{navTriggerMobile}
{/*Replaced by Onilab -- end */}
{pageLoadingIndicator}
<OnlineIndicator
hasBeenOffline={hasBeenOffline}
isOnline={isOnline}
/>
<Link to={resourceUrl('/')}>
<Logo classes={{ logo: classes.logo }} />
</Link>
{/*Added by Onilab - Category navigation only on desktop -- start */}
{categoryNavigation}
{/*Added by Onilab -- end */}
<div className={classes.secondaryActions}>
<SearchTrigger
active={searchOpen}
onClick={handleSearchTriggerClick}
/>
<AccountTrigger />
<CartTrigger />
</div>
</div>
{searchBar}
</header>
);
};
Header.propTypes = {
classes: shape({
closed: string,
logo: string,
open: string,
primaryActions: string,
secondaryActions: string,
toolbar: string
})
};
export default Header;
- Start with the following:
import React, { Suspense } from 'react';
import { shape, string } from 'prop-types';
import Logo from '../Logo';
import { Link, resourceUrl, Route } from '@magento/venia-drivers';
- Replace the relative path with the full path:
// Modified by Onilab - Replace relative path with full path -- start
import AccountTrigger from '@magento/venia-ui/lib/components/Header/accountTrigger';
import CartTrigger from '@magento/venia-ui/lib/components/Header/cartTrigger';
import NavTrigger from '@magento/venia-ui/lib/components/Header/navTrigger';
import SearchTrigger from '@magento/venia-ui/lib/components/Header/searchTrigger';
import OnlineIndicator from '@magento/venia-ui/lib/components/Header/onlineIndicator';
import { useHeader } from '@magento/peregrine/lib/talons/Header/useHeader';
import { mergeClasses } from '@magento/venia-ui/lib/classify';
import defaultClasses from '@magento/venia-ui/lib/components/Header/header.css';
import PageLoadingIndicator from '@magento/venia-ui/lib/components/PageLoadingIndicator';
// Modified by Onilab -- end
- Import the desktop menu component and use WindowSize from Peregrine to detect mobile:
//Added by Onilab - Import desktop menu component and useWindowSize from Peregrine to detect mobile -- start
import {useWindowSize} from "@magento/peregrine";
import TopCategoryNav from "../Menu/topCategoryNav";
//Added by Onilab -- end
- Replace the relative path with the full path once more:
// Modified by Onilab - Replace relative path with full path -- start
const SearchBar = React.lazy(() => import('@magento/venia-ui/lib/components/SearchBar'));
// Modified by Onilab -- end
- Continue by:
const Header = props => {
const {
handleSearchTriggerClick,
hasBeenOffline,
isOnline,
searchOpen,
isPageLoading
} = useHeader();
const classes = mergeClasses(defaultClasses, props.classes);
const rootClass = searchOpen ? classes.open : classes.closed;
const searchBarFallback = (
<div className={classes.searchFallback}>
<div className={classes.input}>
<div className={classes.loader} />
</div>
</div>
);
const searchBar = searchOpen ? (
<Suspense fallback={searchBarFallback}>
<Route>
<SearchBar isOpen={searchOpen} />
</Route>
</Suspense>
) : null;
const pageLoadingIndicator = isPageLoading ? (
<PageLoadingIndicator />
) : null;
- Indicate that the header elements depend on the screen size:
//Added by Onilab - Header elements depends on screen size -- start
const windowSize = useWindowSize();
const isMobile = windowSize.innerWidth <= 960;
const navTriggerMobile = isMobile ? (
<div className={classes.primaryActions}>
<NavTrigger />
</div>
) : null;
const categoryNavigation = !isMobile ? (
<TopCategoryNav />
) : null;
//Added by Onilab -- end
- Depending on the trigger (whether the current screen size is mobile), we display a specific menu, mobile or desktop:
return (
<header className={rootClass}>
<div className={classes.toolbar}>
{/*Replaced by Onilab - Nav trigger obly on mobile-- start */}
{navTriggerMobile}
{/*Replaced by Onilab -- end */}
{pageLoadingIndicator}
<OnlineIndicator
hasBeenOffline={hasBeenOffline}
isOnline={isOnline}
/>
<Link to={resourceUrl('/')}>
<Logo classes={{ logo: classes.logo }} />
</Link>
{/*Added by Onilab - Category navigation only on desktop -- start */}
{categoryNavigation}
{/*Added by Onilab -- end */}
<div className={classes.secondaryActions}>
<SearchTrigger
active={searchOpen}
onClick={handleSearchTriggerClick}
/>
<AccountTrigger />
<CartTrigger />
</div>
</div>
{searchBar}
</header>
);
};
Header.propTypes = {
classes: shape({
closed: string,
logo: string,
open: string,
primaryActions: string,
secondaryActions: string,
toolbar: string
})
};
export default Header;
Step 4: Redesigning the Sign-in Area
In this step, we transfer the user sign-in and user authentication/registration menu to the pop-up format.
a) Install the library for modal windows
First, install the react-modal library, which we will need to display the components in pop-up windows:
yarn add react-modal
b) Create a modal window component
Make a simple modal window component that can easily be expanded and improved if necessary.
import React from "react";
import ReactModal from "react-modal";
ReactModal.setAppElement('#root');
const LoginModal = props => {
const {isOpen, close} = props;
const customStyles = {
overlay: {
zIndex: 999,
},
content : {
top: '50%',
left: '50%',
right: 'auto',
bottom: 'auto',
marginRight: '-50%',
transform: 'translate(-50%, -50%)'
}
};
return (
<ReactModal
isOpen={isOpen}
onRequestClose={close}
style={customStyles}>
{props.children}
</ReactModal>
);
}
export default LoginModal;
c) Change the component
Now we need to re-assign some of the default functionality of the PWA Studio once again. In our example, we take the AccountMenu component and redefine only the one file we need.
Copy this file from:
venia-create-app/node_modules/@magento/venia-ui/lib/components/AccountMenu/accountMenu.js
To:
venia-create-app/src/components/AccountMenu/accountMenu.js
d) Replace relative paths & implement the changes
Make changes in such a way that everything related to authorization and registration will work in the modal window. What’s for the authorized user, the sign-in should stay within the drop-down window (like it was previously before we made changes).
module.exports = componentOverride = {};
4. Building a PWA Using the Magento 2 PWA Studio: Backend Peculiarities
In this section of the blog post, we’d like to show how to create a Magento module that would return a product list shown within the slider.
Step 1: Create a module & the required files
Begin by creating a Magento 2 module. We’ll name it PWA_MyProductList. We need several files that make up the required minimum in Magento 2 to create modules.
- We need a registration.php file.
<?php
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'PWA_MyProductList',
__DIR__
);
- Next, let’s create a module.xml file.
<?xml version="1.0" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="PWA_MyProductList" setup_version="1.0.0">
<sequence>
<module name="Magento_Catalog"/>
</sequence>
</module>
</config>
Step 2: Create schema.graphqls file
Now it’s time to create a file containing the GraphQL schema for the request. This file should also indicate the resolver that’ll process the request.
type Query {
customProductsList: [ ProductsBlock ] @resolver(class: "PWA\\MyProductList\\Model\\Resolver\\ProductsBlock")
}
type ProductsBlock {
name: String
url: String
image: String
id: Int
}
Step 3: Create a resolver
All that’s left at this point is making a resolver responsible for returning the necessary product list.
<?php
declare (strict_types = 1);
namespace PWA\MyProductList\Model\Resolver;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory as ProductCollectionFactory;
class ProductsBlock implements ResolverInterface
{
const PRODUCTS_LIMIT = 10;
/**
* $productCollectionFactory
*
* @var ProductCollectionFactory
*/
private $productCollectionFactory;
/**
* __construct
*
* @param ProductCollectionFactory $productCollectionFactory
*/
public function __construct(
ProductCollectionFactory $productCollectionFactory
)
$this->productCollectionFactory = $productCollectionFactory;
}
/**
* @inheritdoc
*/
public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null)
{
$result = [];
$storeId = $context->getExtensionAttributes()
->getStore()
->getStoreId();
$collection = $this->productCollectionFactory
->create()
->addStoreFilter($storeId)
->addFieldToFilter('customt_attribute', 'custom_value')
->setOrder('sort_order', 'ASC')
->setPageSize(self::PRODUCTS_LIMIT);
foreach ($collection as $item) {
$result[] = [
'name' => $item->getName(),
'url' => $item->getProductUrl(),
'image' => $item->getImage(),
'id' => $item->getId()
];
}
return $result;
}
}
Step 4: Create a GraphQL query
As of now, the product list is returned by Magento 2. For the progressive web app we’re building, we need this to be handled by GraphQl instead. Therefore, create a file that’ll contain such a GraphQL query.
import { gql } from '@apollo/client';
export const PRODUCT_LIST_BLOCK = gql`
query CustomProductsList {
productsBlock {
id
name
url
image
}
}
`;
export default PRODUCT_LIST_BLOCK;
Step 5: Create a Magento query
The final step is creating a Magento 2 query, which allows us to get a product list in the slider.
import React from 'react';
import Swiper from 'swiper/react';
import Loader from "src/Components/General/Loader";
import Error from "src/Components/General/Error";
import useProductList from "src/talons/RootComponents/Homepage/useProductList";
const CustomProductsBlock = () => {
const {loading, error, productsList} = useProductList();
if (error) {
return <Error />;
}
if (loading) {
return <Loader />;
}
const params = {
};
return (
<>
<div className={`pageWrapper`}>
<div className={`containerWrapper`}>
<Swiper {...params}>
<>
{productsList.map(product => {
return <div key={ product.id } className={ 'product-slider' }>
<Link to={ product.url } className={ 'product-image' }>
<img src={product.image} />
</Link>
<Link to={ product.url } className={ 'product-link' }>
{ product.name }
</Link>
</div>
})}
</>
</Swiper>
</div>
</div>
</>
);
};
export default CustomProductsBlock;
Plus, as shown in the file below, create a talon for obtaining the product list:
import { useQuery } from '@apollo/client';
import { useEffect, useState } from 'react';
import PRODUCT_LIST_BLOCK from "src/Queries/GetProductList";
const useProductList = () => {
const [productsList, setProductsList] = useState(null);
const {loading, error, data} = useQuery(PRODUCT_LIST_BLOCK, {
fetchPolicy: 'cache-and-network',
nextFetchPolicy: 'cache-first',
});
useEffect(() => {
if (data) {
setProductsList(data.customProductsList);
}
}, [data]);
return {
error,
loading,
productsList
};
};
export default useProductList;
5. PWA Studio Tips from the Pros
Now that it’s clear how to build a PWA with the use of the Magento PWA Studio, let’s go over some of the recommendations given by the pros. The following block will give more information on how to use the instrument and which mistakes to avoid.
1. Talons or Hooks
The first point in the overview regards what talons are in the Magento 2 PWA Studio and how they differ from custom React hooks.
Put simply, React components have sections for logic and visualization. In the Magento PWA Studio, these components are split into Peregrine Talons (used for logic) and Venia visual components (needed for content visualization). In their turn, Peregrine Talons are a kind of React hooks that provide standard functionality and logic for Venia UI components. Unlike Peregrine Talons, Peregrine hooks can be reused.
You can learn more about talons and hooks
.2. Possible Launching Issues with Windows
When using Windows, you may encounter additional launching problems. In an ideal scenario, you should avoid using the Windows object since it can cause additional problems during the launch. You can take a look at such a
.3. Reusable Constants
It is possible to implement new environment variables, yet there is no proper structure that would allow reusing regular constants in the project. There’s a workaround solution for this. For instance, you can make a “Constants” folder (like we have done in our step-by-step Magento PWA Studio tutorial), define them in it, and then reuse them. The official Magento team brings up one more
that you can also check out.4. Fragmenting GraphQL Queries
The Magento PWA Studio does not use (or hardly ever uses) fragments for
. But you can break large queries into chunks and then reuse them a large number of times.To give an example of when this is applicable, you can use this in case you need to add a field to the requests of all types of product cards. This way, you’ll just add this field to a single fragment.
Make sure to apply this advice carefully when you work on your Magento 2 PWA Studio setup. Do your best to request only the necessary data minimum in your GraphQL queries. Note that if you apply this method without due thought, this may have consequences. For instance, in the case of listings, if you add the description field to the product, you can greatly increase the duration of the
, the load time, and the space occupied in the cache.5. Caching
When handling the caching matter, do not forget about the localStorage limitations. Otherwise, an overflow may occur.
What is more, the caching of some objects must be configured separately for the Apollo cache.
Plus, when you build the webpack, it is possible to cache configurations and the URLs of your resolvers within the environment variables or in the template.
6. Overriding Standard Components
Another thing you should keep in mind is that when you override standard components, there may be extra styles. In turn, this can increase the total weight of the files, which isn’t good. This is why it’s worth investing time in cutting out excessive code blocks with styles.
Final Thoughts
We’ve shown several examples of how to change the web app built with Magento PWA Studio when deploying a progressive web application on Magento 2. If your UX is very different from what Magento PWA Studio offers, then you’ll have to redefine many components this way. As a result, it may turn out that the Magento PWA Studio will be completely redefined, and essentially, you won’t need it. If this is the case, it’ll take a couple of days to tweak it, simplify the code, and reduce the weight of the application.
The theme general design is often accused of being boring, unsightly, and shady, and you may not find the desired typeface or encounter another specific PWA Studio problem. But in any case, the PWA Studio is a great start for those building a progressive web app for the first time. If you need help with
, don't hesitate to contact us and !