The Basics The concept of Progressive Web Apps (PWAs) is a framework agnostic approach which seeks to combine discoverability and accessibility of a website with the functionality of a native app. Since couple of years I see an increasing interest technologies which bridge the gap between web- and native-apps. In 2018 PWAs have made a great step towards mainstream adoption. By now, plenty of companies like , , , , , , have already created PWAs to run parallel to their native apps. Pinterest Uber Twitter Trivago The Washington Post Starbucks The reason is obvious, plenty of these companies report very promising numbers, mostly as astonishing as the of increase in conversions Trivago has seen. 97 percent Why should we start developing PWAs ? now In fact, in 2018 also the majority of browser vendors started backing the technology behind PWAs. Microsoft committed to bring PWAs to “more than running Windows 10”. Google even went as far as calling it the future of app development — no surprise that , Google’s tool for improving the quality of web pages, audits ‘PWA’, next to ‘SEO and ‘Accessibility’ of webapps. And even Apple has finally started to support PWAs in 2018, even though, PWAs are a clear threat to Apple’s app store business. half a billion devices Lighthouse This article is the first part of a tutorial series that teaches you how to develop a PWA in VueJS! Part I — Build the Tax Calculator App in VueJS. Part II — Make the App work offline. Follow me on Medium and you get a notification when Part II will be released! To make it easy for you to follow, check out this . You can checkout a branch for each section! repo The Tax Calculator App In this tutorial we will build an income tax calculator. Why? Because calculating income tax (at least in Germany) is complicated and people would love an app that solves that problem for them. Besides that, it’s also a opportunity to explore the impact of the PWA features mentioned above. We will use VueJS for this tutorial, as it comes with a great template which makes it easy to kick off a PWA project. Another reason is, that VueJS is really easy to learn. No prior experience in any other frontend framework required! Enough theory for now, it’s time to get our hands dirty! Let’s create the App’s Skeleton We start-off with creating the basic setup and the file structure of our app. To speed things up, we will bootstrap the app with vue-cli. First, we need to install the vue CLI tool globally. yarn global add @vue/cli Now we can instantiate the template by vue init pwa vue-calculator-pwa We will be prompted to pick a preset — I recommend the following configuration: ? Project name ? Project short name: fewer than 12 characters to not be truncated on homescreens (default: same as name) ? Project description A simple tax calculator? Author Fabian Hinsenkamp ? Vue build runtime? Install vue-router? No? Use ESLint to lint your code? Yes? Pick an ESLint preset Standard? Setup unit tests with Karma + Mocha? No? Setup e2e tests with Nightwatch? No vue-calculator-pwa vue-calculator-pwa fabian.hinsenkamp@online.de For the configuration we can choose the smaller option as we don’t need the compiler as the html we write inside our files is pre-compiled into at build time. Vue build runtime *.vue JavaScript We don’t add tests here for brevity reasons. If we would set up a project for for production definitely add them. Next, run to install all dependencies. To start the development mode just run . yarn yarn start Don’t get confused by all the files in the project — For now we won’t touch most of them. If you want to learn more about the template’s structure check out the . I can only recommend it! documentation In the project we will find files with the extension. It indicates that this file is a single-file vue component. It is one of the Vue’s features. Each file consists of three types of blocks: , . That way, we can easily divide the project into loosely-coupled components. .vue <template> <script> <style> Let’s start creating all the files our app consists off. *.vue App.vue Create the file . It is our main view and it will contain our different components which make up our calculator. src/App.vue InputForm.vue Next let’s create the inputForm file . It will handle all user inputs required to calculate the income taxes. src/components/InputForm.vue Moreover, we create skeleton files for the following , , components including a style sheet named identically to the component it belongs to. All of them belong into the folder. .vue Result Panel Input src/components Result.vue It will display the results of our calculations. Panel.vue & Input.vue The panel is a simple component that wraps the input and result components. Finally, we should remove the file, that comes with the vue template. Hello.vue Add Styles & Calculation Logic Next, we add the following libraries to support sass/scss files. yarn add node-sass sass-loader -D For now, the scss files we added are all empty. I won’t talk about styles in this tutorial as there is nothing specific about applying styles to app. Hence, you have two options, create your own styles or checkout the following branch of the . github project git checkout 01_skeletonApp We also need logic to calculate our income tax. I use the real German income tax formular. To spare the details, I also added it to the branch. It also contains some css animations for the input validation message. In case you don’t want to use the branch above, you can also add them manually: yarn add animation.css Let’s create the Panel Component! Now we can start coding! To warm you up, we start with building the panel component. It’s good practice to keep such components generic so it can be reused holding any kind of content. That’s why we aim to pass the headline as well as the html for the body to the component. Let’s add the following code to the template section of the file. panel.vue For one-way data binding in , we can use . That’s exactly what we do to render the headline. Therefore, we simply need to wrap our headline data object in double curly braces. Attention, this “Mustache” syntax interprets data always as plain text, not HTML. VueJS textinterpolation That’s why we also use vue’s element, which allows us to render child elements of our panel component within the body element. Now we are done with the html for the panel component, next we define our script logic. slot First, it’s important to add a name to the component so we can actually register the component and import it later on. As we want to pass the headline to the panel, we should specify it as properties. Properties are custom attributes we can register on a component. To see the panel in our app, just add the code above to our component. app.vue In the script block we already import the component so adding the html is all we need to add our first component to the app! We should see the panel when we run . yarn start If we have any problems implementing the panel or want to skip this section check the following branch. git checkout 02_panel Let’s create the Input Component! Next we build our input form with some neat custom input validation. We have three types of inputs: regular, select and radio. Except the radio buttons these inputs need input validation and corresponding user feedback. To avoid repeating ourselves, we should build a reusable input component. To build a component which is actually reusable, I advice to build it in a way, that allows to easily extend it without changing the whole architecture. Defining a clean and thought through component api is a great starting point. In our case, we always want to control four properties from outside of the component: label input type validation rule data-binding Let’s translate these requirements into code! The component looks like the following: input.vue We add some custom vue-attributes to the native input component. First we add , which allows us to render the input only if we pass the correct type to our component. This is important to add different types of inputs. Next, we to the component’s event with the to a method called . v-if bind input @-prefix customInput Thats where our custom input validation comes to play. We add a validation library to the project by running and register the plugin in our file. yarn add vee-validate main.js Our validation consists in intercepting the native input event and then check if the entered values meet our validation rule. In case it doesn’t we set an error message. Therefore, we add two methods to the file. The method is triggered when the user enters any input. input.vue customInput The validation error message is returned from the plugin. We only have to add some html to show it to the user: v-validate I add a transition to the error message. VueJS comes with a transition wrapper, combined with the flip-animation from and some styles, we can get a nice error message without any hassle. animate.css To add the new input to the app, register the completed Input component to the . Here we apply two-way-binding through — It automatically picks the correct way to update the element based on the input type. Now, we need to open , import as we did with and replace with . InputForm.vue v-model App.vue InputForm Panel <span> content goes here. </span> <InputForm/> The result should look like what you see here on the left side. Check the branch for more details! git checkout 03_basicInput Add more input types! Now that we have a basic input with validation in place, it’s easy to extend our input component with the remaining two input types — the select and radio input. For the select element we use an out-off-the-box component. We simply add it by running: yarn add vue-select Before we can use it, it needs to be registered in the file similar to the plugin before. However, this time we use the method. main.js v-validate Vue.component Now simply add the component to our file. The options we want to show in the dropdown will be passed to the component as props. Input.vue Now there are only the radio buttons left to add. // image We start off with the native html element. Even though we just need two radio buttons atm, I advice to build the component in a way that allows to pass an arbitrary number of inputs. Therefore, we simply use vue’s attribute to loop over the options property and create a radio button for each element of the option array. v-for Additionally, we need to pass the currently selected value in order to manage the ‘checked’ state of the radio button inputs. In the script block we add an array holding all possible value types. To test our new input types, we need to actually add them to the submit form and pass options to the select and radio input. Check out the file in the following branch to see how the options are passed to the new inputs. inputForm.vue git checkout 04_completeInputs It follows the same pattern we have investigated for the regular input in detail. Most importantly, keep in mind to always pass an object containing a value and a label. That’s it! We managed to create a component that allows us to add all the input types we need and validate them without repeating ourselves! Let’s finalise our input form! Now we can finalise the input form. The only thing missing is the button to submit the form. We start with preventing the default html form event, and call our custom method instead. handleSubmit There we clean our input results — Although our dropdown and radio buttons require return objects with label and value, we are only interested in the value to calculate the results. Finally, we create a custom event which emits only the values of our input options. We also create a computed property which enables our “calculate” button only after all required data is entered by the user. You find the completed input form on the branch I mentioned already above. git checkout 04_completeInputs Let’s calculate our taxes! Now we are already able to get the inputs from the user, next we need to actually calculate the resulting income taxes. As I mentioned in the very beginning, I want to spare you the details about how the different types of deductions are calculated. In case you are interested anyhow check out the file. calc.js Most importantly, we understand that we use the custom event to pass the inputs back to our component. Here we also calculate the actual taxes and store the resulting values with labels, and add negative signs to the values we deduced from the gross income. submitted app.vue — Why? It makes displaying the results very simple as we will see in the next section. Let’s display our Results! Now we have everything we need to finally show the results of our tax calculations. Therefore, we use a native html table to show the label and the corresponding value in a structured manner. The implementation is quite simple, as we can stick to what we have learned about VueJS already. In fact, we repeat what we have done for the radio input already. We just pass our calculations as props to the component and loop over our results object. results As users probably want to perform multiple calculations without refreshing the page, we add another button, that leads users back to the input form. Therefore, we simply emit a custom event called to clear our calculations property in the parent component. Finally, we are also tying all our components together and complete our income tax calculator. clearCalculations As always, checkout the branch I you want to have a more detailed look at the code. git checkout 05_result Let’s finalise our App! In this last section there is only, two things left to do — complete the data-flow and manage the lifecycle of the input and result component accordingly. in the component we just added a button which emits the event. On the left, we see our main component . Here we subscribe to the event and reset the calculations object to be empty. Result.vue clearCalculation App.vue Now, we want to only render the input or the result component. Therefore, we add another boolean property, which checks if we have calculation results or not. computed Now, we add attributes to our components based on our prop. v-if resultsCalculated Try it out! Now we should see the table with the results only after we have successfully entered our inputs. To make the switch between input and results less harsh we add a transition. As we are replacing the one with the other component here, we use the attribute so that, the current element transitions out first, then when complete, the new element transitions in. mode out-in We completed the tutorial! Well done! The branch with the finale application code is the following git checkout 06_complete Conclusion We have successfully kickstarted the implementation of our income tax calculator PWA based on vue’s PWA template. Thereby, we familiarised ourselves with the syntax and paradigms of VueJS. So far so good but we are still far-off from providing a user experience close to a native app. This is what of this tutorial will focus on. Part II If you want to be notified when Part II is released — just follow me here on Medium or follow me on Twitter ! @Fa_Hinse