CX & Design June 08, 2018
Shopware & React: A Beautiful Combination
Online shops today are accessed via a variety of devices. For us developers, this often means twice the work to provide the customer with a satisfying and engaging user experience on every occasion. So why not create one and the same solution for all?
A constant state of flux
In times when modern browsers feel like operational systems themselves, it is quite common to use single page apps instead of smartphone applications. Technologies like React, Vue and the like enable us to create a fluid, even app-like experience whilst browsing the web.
One and the same solution for every device — and it should look and feel amazing.
Instead of having to create a different look for each device, we liked the idea of maintaining one and the same version of the platform, suitable for everyone. To find a solution, we had to break new ground. Fortunately, our client Dorothee Schumacher was willing to join us on our journey.
There was only one requirement: “We want to use Shopware!” However, Shopware provides a storefront based on templates and therefore is not ready for single page apps by default — there are simply no REST APIs you could use.
We were fiercely determined to make it work, nonetheless. Thus, the past year was an exciting time packed with new experiences, valuable insights — and also some annoying setbacks.
Our journey begins — how to combine Shopware and React
First there was light. Okay, we were quite lost in the beginning, to be honest. We knew how to create a shop based on the Shopware system, we had worked with React, but we had never used React in combination with Shopware before.
Shopware pretty much provides you with ready-made templates. The React application, on the other hand, is built using a custom webpack setup and is implemented with the Redux data flow paradigm in mind. So, we had to break new ground and start from scratch. We removed almost everything that came with the Shopware template by default and created a new template with the sole task of loading the React application.
No matter the app-like beauty of free-flowing data, wanting to buy things on the internet and browsing a shop, you expect to find the most important elements (e.g. the main navigation) straight away. Consequently, we created an initial state object being filled using the standard Shopware way of assigning data gathered in the PHP code to a view.
Heureka — we had managed to link the shop to our very own React app.
Next, we focused on integrating the more dynamic data. To do so, we had to create REST API endpoints in Shopware. As each page load can result in a bunch of sub-requests, performance and simplicity were the key factors here. In total, we created roundabout 20 different REST API endpoints, each with different caching rules. Some of them are used within the main application, others in components.
Architecture: How not to repeat that ole Babel thing (and we’re not talking JS here)
To keep the different sections of the shop separated, we had to come up with an easy and strict component structure. Each section, the product detail pages, for instance, was built within its own React component. The main application just reacts to URLs passed to the React router and then mounts the relevant lazy load components.
But first of all, we had to make sure the project wouldn’t turn out to be a second Tower of Babel. Shopware and React don’t speak the same language, we therefore had to moderate. Since Shopware uses a clean URL system, we needed to find a way to tell the router which component to mount via the given URL. Accordingly, we created a page route regarding the original URL as an argument. Each page type had to be routed to its matching component which then would receive the specific props and call the API for more data, if required.
Sounds like a bunch of work? You bet.
Troubleshooting on the go
Whenever you create a platform based on a standard e-commerce system, you need to make sure that the standard functions really work within the context of your application. In our case, this — unfortunately — meant a severe blow to our time constraints. Was there an elegant and easy way out? We tried different approaches to create hybrid parts of the app.
Could a hybrid be a nostrum?
The first idea was to have two identical headers — one built within the React application, the other one inside the Shopware template. This way, the parts of the webshop not suitable for React (checkout, for instance) and the ones where React’s app-like smoothness kicked in looked and felt the same on the outside, even though they were fundamentally different, bigger on the inside, if you want to (think the TARDIS, but in two parallel universes).
Sounds beautiful? It wasn’t, to be honest. The header itself was far too complex and all its logic and many components alone would have blown our timing.
The solution at hand was to create an iFrame component, allowing us to render different parts of the shop without having to implement every single bit inside as well as outside of React.
Losing our head over headers
What first seemed to be a promising approach proved that the old saying about the devil being in the detail is there for a reason (it was the details that almost killed us). In our case, the devil — and also some of his friends and relatives — were in the header. The shop being able to display a page with or without the header (using a switch operated by an URL parameter) and the iFrame component being able to handle requests as well inside as outside of its own turned out to be quite a surprising combination. Parts of Shopware rely on redirecting after certain actions have taken place — which broke our application and more than once lead to multiple headers displayed at once. Or none at all. The only way out of being either buried by an avalanche of headers or bewailing the total lack of them was to rewrite requests to include the iFrame parameter.
At that point, the coffee maker shuffled off this mortal coil.
Everything for elegance — a rocky road to a beautiful result
We were determined to implement one of the core features of Shopware (“emotions”) in React as well, which proved to be a great challenge, as the content displayed on the different end devices varied. In order to present the products in the best possible way on each device used by the customer, the page display in some cases had to be fundamentally different from the possibilities suggested by Shopware. An emotion consists of several elements which we translated into React components receiving the data. Each time the device or viewport changes, new data is requested from our emotion API and all components are re-rendered accordingly.
We’re all in this together — and, hooray, we did it!
Of all projects we had ever been involved with, this one was one of the most demanding — but also one of the most rewarding. React combined with Shopware was a novelty for us, and throughout our journey we often wondered where the next turn would lead us.
The process began a little bumpy, as we really had to dwell over the architectural decision. How do you set up the architecture for such an extensive and complex project? It took us a lot of time to finally come up with the best solution.
The biggest challenge with the fusion of Shopware and React was that in the beginning, we had no clear idea what the result would look like in the end. We could have saved a lot of time and avoided a lot of stress if we hadn’t behaved like a curious pile of chickens at the start of the project. Instead of working out a definite plan, we started out a little light-headed, going with the flow, dealing with obstacles as we stumbled upon them on our way. The overall architecture we were working on was rather complex, and integrating the parts of the shop built outside React (e.g. the store locator) seemed nearly impossible — until we found the right approach: to use iFrames.
When the project started, the technology to be used was not yet clearly defined. Accordingly, UX, UI, frontend and backend had to work closely together with the customer, who — fortunately — was open to agile working methods with short-term changes. The interdisciplinary approach of the project was very valuable for our work. Also, using Scrum was of great advantage. Readjustments during sprints were possible at any time.
We learned a lot throughout the process — first of all, that it is always a good idea to step outside your own bubble and listen to people approaching the subject from a different angle. And for the next time, we solemnly vow to sit down right at the beginning and meticulously plan the architecture on the drawing board. And to buy a more powerful coffee machine.
You can find the project here.
Facts & figures
- Frontend: 3 (including several part-time workers)
- Backend: 2
- UI: 2 (including part-time workers)
- UX: 2
- PO: 1
- Scrum-Master: 1
- PHP: 59.93 %
- Smarty: 4.39 %
- CSS: 4.08 %
- HTML: 1.15 %
- Commits: ~2000
- Sprints: 8