My first real job in the programming industry was at a startup that demanded the world of me. I began with them as one of those simple wordpress theme changer guys before quickly being given all the hats. The product was a loyalty-rewards program for merchants. We added a text-message marketing tool for blasting campaigns to the rewards members, and then the last project I worked on with them was a full online-ordering system. This story-tutorial is about how I executed the online ordering app.
The Online Ordering app is a Vue SPA built with the CLI v3. It uses Vuex, Vue Router ( of course ), the official PWA plugin, and it’s demo can be found at https://demo.orders.realmobiletech.com/m/galaxy.
So how does this use Laravel? Well, after building this ordering app for one of our clients, we had to give it to another.. Furthermore, we had to provide a sort of ‘white-labellable’ experience for all of our clients who used this webapp. Usually you would just load the merchant’s specific data ( their menu, their styles, their whatever ) upon either a successful login or a route to their specific home-page. However, how would you get the PWA aspect of this to work in a white-label fashion? The PWA icon that gets installed to the homescreen is determined by the app manifest, and there’s no client-side way of dynamically generating that ( as far as I was able to tell from researching into it ).
That simply meant that I needed to uproot the entire SPA and shove a server behind it… and luckily for me Evan You ( bless this man ) did a basic showcase of using the new Vue CLI v3 with a base laravel installation. I cloned it, and replaced the vue ‘frontend’ folder with my pre-existing SPA, then replaced both the index page and the manifest.json with blade templates so that the Laravel app would dynamically generate them with every request to the server.
I’ll show you a few code examples of how I did this. Hopefully this inspires more people to use both Vue and Laravel to create awesome applications for large industries. I hope I can use this to show everyone how it is possible to create a white-labellable experience for your clients using the same code base.
A couple things to note here. First off, the back-end to this application was built with a separate installation of CakePHP 2.x. If I was to redo this all over again starting from scratch, I would have built the entire API within this same Laravel installation that is serving the PWA. In that situation, there would be many more to the infrastructure of the Laravel backend. For this instance, the Laravel installation deals exclusively with serving a dynamic PWA. Secondly, let me explain how this works:
The app is hosted at https://orders.realmobiletech.com. In order to ‘visit’ a specific merchant I created a ‘middleware’ of sorts with the /m/ route, and then the name of the merchant after that. Laravel picks up on the ‘merchant slug’ ( the part after the /m/ ) and grabs the correct files to serve with the manifest. On the client-side, the SPA will load the merchant’s information based on that slug being passed to it. If it does not find a merchant that matches it, it will serve a 404 page. That is soon to change as the 404 page is currently being replaced with a generic ‘choose a merchant from this list’ page.
The intention is to have the icon files hosted on a separate CDN, not within the Laravel installation itself ( as you see with the file path for each icon ), but we haven’t gotten there yet. The goal is to follow the advice from section 7.1.1 in https://www.w3.org/TR/appmanifest/ and the example code from https://github.com/rossta/serviceworker-rails/issues/40.
Also, note the ‘scope’. This basically means that every ‘installation’ of the code will have it’s own space in browser memory for IndexedDB and localStorage. This is tested. So I have all of those merchant’s menu’s loaded on my phone, separately.
As for the index page, it is a blade template that is created by the build process of the Vue CLI v3
As for the front-end routing in Vue, the routes will take the :slug dynamically, and will pass it along with every router request. If the :slug is not identified as anyone who actually exists, it will redirect you to the ‘not-found’ page ( that is soon to be a ‘choose-someone’ page )
Hopefully this helps someone. Thank you for the read!