Vue.js Web Development Projects Learn Vue.js by building web apps Guillaume Chau BIRMINGHAM - MUMBAI Vue.js Web Development Projects Copyright © 2017 Packt Publishing All rights reserved No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews Every effort has been made in the preparation of this book to ensure the accuracy of the information presented However, the information contained in this book is sold without warranty, either express or implied Neither the author, nor Packt Publishing, and its dealers and distributors will be held liable for any damages caused or alleged to be caused directly or indirectly by this book Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals However, Packt Publishing cannot guarantee the accuracy of this information First published: November 2017 Production reference: 2081217 Published by Packt Publishing Ltd Livery Place 35 Livery Street Birmingham B3 2PB, UK ISBN 978-1-78712-746-3 www.packtpub.com Credits Author Guillaume Chau Copy Editor Dhanya Baburaj Reviewer Eduardo San Martin Morote Project Coordinator Sheejal Shah Commissioning Editor Ashwin Nair Proofreader Safis Editing Acquisition Editor Shweta Pant Indexer Tejal Daruwale Soni Content Development Editor Arun Nadar Graphics Jason Monteiro Technical Editor Diksha Wakode Production Coordinator Shantanu Zagade About the Author Guillaume Chau is the creator of integrations with Meteor (vue-meteor) and Apollo GraphQL (vue-apollo) to help developers build highly interactive, real-time, Vue-powered apps He also created the official vue-curated app , which helps you to discover great packages, and he contributes to the ecosystem with tools such as vue-virtual-scroller and vue-supply He built a customer portal app for a big energy company with large datasets and performance challenges and is now working with an innovative French start-up (WebRTC and real-time data) First, I would like to thank my partner With her constant support and love, I was able to get through the huge amount of work required to write this book I would also like to thank my parents, my family and my friends for their support as well, and also the other Vue.js Core Team, and more specifically Posva for his technical review of the book, the Packt staff members I worked with, and my very cute black and white cat About the Reviewer Eduardo San Martin Morote is a frontend developer who loves open source He has been contributing to open source since he started crafting applications He mostly maintains Vue.js-related projects as Vue itself, vuefire, and vue-router When he develops applications, he likes to focus on UX, and always works in a pragmatic way He tends to reduce waste as much as possible by applying the lean methodology wherever he can He also trains people in web development, and is patient and adapts his teaching to different levels www.PacktPub.com For support files and downloads related to your book, please visit www.PacktPub.com Did you know that Packt offers eBook versions of every book published, with PDF and ePub files available? You can upgrade to the eBook version at www.PacktPub.com and as a print book customer, you are entitled to a discount on the eBook copy Get in touch with us at service@packtpub.com for more details At www.PacktPub.com, you can also read a collection of free technical articles, sign up for a range of free newsletters and receive exclusive discounts and offers on Packt books and eBooks https://www.packtpub.com/mapt Get the most in-demand software skills with Mapt Mapt gives you full access to all Packt books and video courses, as well as industry-leading tools to help you plan your personal development and advance your career Why subscribe? Fully searchable across every book published by Packt Copy and paste, print, and bookmark content On demand and accessible via a web browser Customer Feedback Thanks for purchasing this Packt book At Packt, quality is at the heart of our editorial process To help us improve, please leave us an honest review on this book's Amazon page at www.amazon.in/dp/178712746X If you'd like to join our team of regular reviewers, you can email us at customerreviews@packtpub.com We award our regular reviewers with free eBooks and videos in exchange for their valuable feedback Help us be relentless in improving our products! Table of Contents Preface Chapter 1: Getting Started with Vue Why another frontend framework? A trending project Compatibility requirements One-minute setup Creating an app Vue devtools Templates make your DOM dynamic Displaying text Adding basic interactivity with directives Summary Chapter 2: Project - Markdown Notebook A basic note editor Setting up the project The note editor The preview pane Computed property Text interpolation escaping Displaying HTML Saving the note Watching changes Using a method Accessing the Vue instance Loading the saved note Lifecycle hooks Initializing directly in the data Multiple notes The note list A method to create a new note Button and click events with v-on Binding attributes with v-bind Displaying a list with v-for Selecting a note The current note Dynamic CSS classes 6 8 10 12 12 13 15 16 17 18 19 20 20 21 22 23 24 27 27 28 29 30 31 31 32 33 34 36 38 39 40 Table of Contents Conditional templates with v-if Saving the notes with the deep option Saving the selection The note toolbar with extras inside Renaming the note Deleting the note Favorite notes The status bar Created date with a filter Text stats Summary Chapter 3: Project - Castle Duel Browser Game Rules of the game Setting up the project The calm before the storm The template option The app state The almighty components Building the user interface Our first component - the top bar Adding some gameplay data to the state Defining and using the components Parent-to-child communication with Props Props in our template Displaying a card Listening to native events on components Child-to-parent communication with custom events The hand Animating the hand with transitions A prettier animation Playing a card Animating the card list The key special attribute The CSS transitions The overlays Content distribution with slots The 'player turn' overlay The 'last play' overlay The 'game over' overlay Dynamic component The overlay animation Key attribute The overlay background [ ii ] 41 43 45 46 46 48 49 52 53 55 57 58 58 62 63 63 63 66 66 67 67 68 70 71 72 76 76 78 81 85 87 88 89 91 92 93 95 96 96 97 100 100 101 Project - Real-time Dashboard with Meteor Chapter The component should look like this: If you click on the buttons, nothing visible should happen Inspecting the data There is an easy way to check whether our code works and to verify that you can add items in the Measures collection We can connect to the MongoDB database in a single command In another terminal, run the following command to connect to the app's database: meteor mongo Then, enter this MongoDB query to fetch the documents of the measures collection (the argument used when creating the Measures Meteor collection): db.measures.find({}) If you clicked on the buttons, a list of measure documents should be displayed: [ 361 ] Project - Real-time Dashboard with Meteor Chapter This means that our Meteor method worked and objects were inserted in our MongoDB database Dashboard and reporting Now that our first page is done, we can continue with the real-time dashboard Progress bars library To display some pretty indicators, let's install another Vue library that allows drawing progress bars along SVG paths; that way, we can have semi-circular bars: Add the vue-progress-path npm package to the project: meteor npm i -S vue-progress-path We need to tell the Vue compiler for Meteor not to process the files in node_modules where the package is installed Create a new vueignore file in the project root directory This file works like a gitignore: each line is a rule to ignore some paths If it ends with a slash /, it will ignore only corresponding folders So, the content of vueignore should be as follows: node_modules/ Finally, install the vue-progress-path plugin in the client/main.js file: import 'vue-progress-path/dist/vue-progress-path.css' import VueProgress from 'vue-progress-path' Vue.use(VueProgress, { defaultShape: 'semicircle', }) Meteor publication To synchronize data, the client must subscribe to a publication declared on the server A Meteor publication is a function that returns a Meteor collection query It can take arguments to filter the data that will be synchronized [ 362 ] Project - Real-time Dashboard with Meteor Chapter For our app, we will only need a simple measures publication that sends all the documents of the Measures collection: This code should only be run on the server So, create a new server in the project folder and a new publications.js file inside that folder: import { Meteor } from 'meteor/meteor' import { Measures } from ' /lib/collections' Meteor.publish('measures', function () { return Measures.find({}) }) This code will only run on the server because it is located in a folder called server Creating the Dashboard component We are ready to build our ProductionDashboard component Thanks to the vuemeteor-tracker we installed earlier, we have a new component definition option-meteor This is an object that describes the publications that need to be subscribed to and the collection data that needs to be retrieved for that component Add the following script section with the meteor definition option: export default { meteor: { // Subscriptions and Collections queries here }, } Inside the meteor option, subscribe to the measures publication with the $subscribe object: meteor: { $subscribe: { 'measures': [], }, }, [ 363 ] Project - Real-time Dashboard with Meteor Chapter The empty array means we pass no parameter to the publication Retrieve the measures with a query on the Measures Meteor collection inside the meteor option: meteor: { // measures () { return Measures.find({}, { sort: { date: -1 }, }) }, }, The second parameter of the find method is an options object very similar to the MongoDB JavaScript API Here, we are sorting the documents by their date in descending order, thanks to the sort property of the options object Finally, create the measures data property and initialize it to an empty array The script of the component should now look like this: import { Measures } from ' / /lib/collections' export default { data () { return { measures: [], } }, meteor: { $subscribe: { 'measures': [], }, measures () { return Measures.find({}, { sort: { date: -1 }, }) [ 364 ] Project - Real-time Dashboard with Meteor Chapter }, }, } In the browser devtools, you can now check whether the component has retrieved the items from the collection Indicators We will create a separate component for the dashboard indicators, as follows: In the components folder, create a new ProductionIndicator.vue component Declare a template that displays a progress bar, a title, and additional info text: {{ title }} {{ info }} Add the value, title, and info props: export default { props: { value: { type: Number, required: true, }, title: String, info: [String, Number], }, } Back in our ProductionDashboard component, let's compute the average of the values and the rate of errors: computed: { length () { return this.measures.length [ 365 ] Project - Real-time Dashboard with Meteor Chapter }, average () { if (!this.length) return let total = this.measures.reduce( (total, measure) => total += measure.value, ) return total / this.length }, errorRate () { if (!this.length) return let total = this.measures.reduce( (total, measure) => total += measure.error ? : 0, ) return total / this.length }, }, In the preceding code snippet, we cached the length of the measures array in a length computed property Add two indicators in the templates - one for the average value and one for the error rate: Production Dashboard [ 366 ] Project - Real-time Dashboard with Meteor Chapter Don't forget to import ProductionIndicator into the component! The indicators should look like this: Listing the measures Finally, we will display a list of the measures below the indicators: Add a simple list of elements for each measure, displaying the date if it has an error and the value: {{ item.date.toLocaleString() }} {{ item.error ? 'Error' : '' }} {{ item.value }} [ 367 ] Project - Real-time Dashboard with Meteor Chapter The app should now look as follows, with a navigation toolbar, two indicators, and the measures list: If you open the app in another window and put your windows side by side, you can see the full-stack reactivity of Meteor in action Open the dashboard in one window and the generator page in the other window Then, add fake measures and watch the data update on the other window in real time If you want to learn more about Meteor, check out the official website (https://www meteor.com/developers) and the Vue integration repository (https://github.com/meteorvue/vue-meteor) [ 368 ] Project - Real-time Dashboard with Meteor Chapter Summary In this final chapter, we created a project using a new full-stack framework called Meteor We integrated Vue into the app and set up a Meteor reactive collection Using a Meteor method, we inserted documents into the collection and displayed in real-time the data in a dashboard component This book may be over, but your journey using Vue is only beginning We started with very basic concepts around templates and reactive data, writing simple applications without any build tools Even with not much baggage, we were able to make a Mardown Notebook and even a browser Card Game with animations Then, we started using the full set of tools at our disposal to make larger apps The official command-line tool vue-cli was a great help in scaffolding our projects The Single-File-Components (.vue files) make the components easy to maintain and evolve We can even use preprocessing languages, such as stylus, very easily The vue-router official library is mandatory for managing multiple pages, like we did in Chapter 5, Project - Support Center, with a nice user system and private routes Next, we went to a whole other level with advanced features, such as Google OAuth and Google Maps, while architecturing our Geolocated Blog in a scalable and safe way using the official Vuex library Then, we improved the quality of our Online Shop code with ESLint and wrote unit tests for our component We even added localization and server-side rendering to the app, so now it has a very professional feeling You can now practice on the projects we built by improving them, and you can even start your own Using Vue will improve your skills, but you can also attend events, chat online with the community, get involved (https://github.com/vuejs/vue), or help others in learning Vue Sharing your knowledge will only increase your own, and you will become better at what you [ 369 ] Index A app creating Vue devtools 10 Vue.js devtools 12 asynchronous operations 247 awesome-vue URL 149 B blog posts, Geolocated Blog app creating 268 BlogMap component changes about 281 click handler 282, 283 ghost marker 283, 284 BlogMap component mapping 265 BlogMap module actions 265 mutations 264 BlogMap, connecting to store about 261 BlogMap module and component 264 user position 266 Vuex modules 261, 262 C card child-to-parent communication, with custom events 76, 78 displaying 72, 74 native events, listening on components 76 playing 87 Castle Duel Browser Game, scenery components animated clouds 110, 112 animation 112, 114 banner bars 107, 108 castle banners 103 castles 102 food and health bubbles 105, 106 value, animating 108, 110 Castle Duel Browser Game card effect, applying 120 card transition, ending 119 card, playing 116 card, removing from hand 118 cards, drawing 115, 116 cheating, avoiding 117 endGame function 124 gameplay 114 nextTurn function 121 overlay close actions 123 project, setting up 62 rules 58, 61 scenery components 101 skipTurn 121 code-splitting about 326 with dynamic imports 327 commit 243 commit mutations 247 computed property 20 D dashboard about 362 component, creating 363 indicators 365 measures, listing 367 Meteor publication 362 progress bars library 362 data-binding 13 development environment code editors 126 command-line tool 126 setting up 125 vue-cli, installing 126 development workflow about 309 app, launching 311 browsers, targeting with browserslist 313 code quality, enhancing with ESLint 314 CSS, auto-prefixing with PostCSS 312 development API, generating 310 project, setting up 310 style, enhancing with ESLint 314 unit testing, with Jest 320 directives used, for adding basic interactivity 13 DOM basic interactivity, adding with directives 13, 14 templates, using 12 text, displaying 12 E ESLint code quality, enhancing 314 configuring 315 executing 316 inside Webpack 317 keywords 323 rules, customizing 316 style, enhancing 314 F FAQ page animation, loading 165 API, consuming 160 code, resusing with mixins 170 error management 175 fetch API, using 161, 165 fetch method 169 fetch, reusing with mixins 172 management, loading 174 plugin options 168 plugin, creating 167 remote data, fetching 172 server, setting up 160 Vue, extending with plugin 167 filters 54 Front-end JavaScript frameworks URL functional components about 302, 303 creating 303, 304, 305, 306 store changes, for comments 302 G Geolocated Blog app about 231 basic structure, setting up 232 blog posts, adding 268 comments, adding 268 creating 233, 234 Google Auth and state management 232 Google Maps, embedding 258 routing 235, 237 state management, with Vuex 237 user system, adding 250 Google Maps API key, obtaining 258 BlogMap, connecting to store 261 embedding 258 installing 258 library, installing 259 map, adding 260, 261 I internationalization about 326 Language page, modifying 331 user locale, loading automatically 329 J Jest Babel, configuration 321 configuring 320 keywords 323 [ 371 ] snapshots 324 snapshots, updating 325 unit testing 320, 322 JSX about 270, 276 blog content structure 277, 279 no content 280 L linting 314 M markdown note app about 17 attributes, binding with v-bind 34 button, used for calling method 33 click events, used for calling methods 33 conditional templates, with v-if 41, 43 current note 39 data, initializing 30 dynamic CSS classes 40 lifecycle hooks 29 list, displaying with v-for 36 method, used for creating note 32 method, using 27 multiple notes 31 note list 31 note toolbar 46 note, saving 23 note, selecting 38 notes, saving with deep option 43 preview pane 20 project, setting up 18 saved note, loading 28 selection, saving 45 status bar 52 text editor, adding 19 Vue instance, accessing 27 watchers 24 Marked URL 20 Meteor about 353 installing 353 project, creating 354 routing 356 URL 353, 368 Vue Meteor app 355 methods using 27 mutation about 243 strict mode 244, 245 N namespaced module 262 note toolbar, markdown note app favorite notes 49, 51 note, deleting 48 note, renaming 46 npm URL 133 P post details about 295 PostContent component 296, 298 store changes, for post selection and sending 295, 296 post, creating about 280 BlogMap changes 281 draft store actions 280 post form 284, 285 request, creating 287, 288 post, selecting about 295 functional components 302 location info 298 post details 295 scoped slots 298 posts store module 268, 269 posts, fetching about 288 login action, implementing 294 logout action, implementing 293 markers, displaying 291, 292 store action 288 [ 372 ] user logging in or out 292 posts-fetching action creating 288, 290 dispatching 290, 291 preview pane about 20 computed property 20 HTML, displaying 22 text interpolation, escaping 21 production measures about 358 collection, adding 359 data, inspecting 361 data, setting up 358 Meteor collections integration 358 Meteor method, adding 359 simulating 360 progressive framework project structure about 147 active class 159 layouts, with router-view 150 navigation menu, creating 156 pages 149 router links 157 router modes 155 router object 154 routes, creating 152 routing 149, 150 setting up 148 Vue plugins 149 props parent-to-child communication 70 using, in template 71 R read-only 241 render functions about 270 data objects 272, 274 dynamic templates 271, 272 used, for writing view in JavaScript 270, 271 Virtual DOM 275, 276 S scoped slots for passing data to parent 298, 300 implementing 300, 302 Search Engine Optimization (SEO) 332 Server-side Rendering (SSR) about 332 app, executing 344 client entry file 335 Client, configuration 340 express server 342 npm scripts 348, 349 page template 342 production build 346 Production build, configuration adding 346 production express server 347 renderer, creating 343 renderer, updating 343 server entry 336 Server, configuration 340 server-side setup 341 state management 336 style, extracting into CSS files 346 Universal App Structure 333 unnecessary fetch, avoiding 345 Vue app, rendering 344 Vuex state, restoring on client 338 Webpack, configuration 339 Single-File Component (SFC) about 134 component, using inside component 143, 145 JSX 138, 139 less 142 preprocessors, adding 141 pug, using 137 sass 142 scoped styles 140 script 137 style 139 stylus 143 template 136 state management, Geolocated Blog app actions, for store operations 247 getters, for computing and returning data 246, [ 373 ] 247 helpers, mapping 248, 249, 250 mutations update 243 single source of truth 241 time-travel debugging 245, 246 Vuex Store 239, 240 with Vuex 237, 238 status bar, markdown note app date filter, using 53, 55 text stats 55 support tickets, login forms fetch plugin, improving 194 form input component 182, 186 login component 187, 191 login operation 196 scoped elements, styling 192 sign up operation 195 smart form 179 v-model, customizing 187 support tickets about 177 adding 204 attributes, binding 214 displaying 204 dynamic remote data 221 dynamic route 223, 226 dynamic routes, with parameters 220 form textarea 213 form, sending 212 guest routes 203 login forms 179 logout method 197 meta properties, routing 199 navigation guard, fixing 211 nested routes 208 not found page 227 plugin 178 private routes with navigation guards 198 route, redirecting 202 router navigation guards 200, 201 routing features 219 scrollBehavior function 228 session expiration 206 tickets list 204 transitions 228 user actions 215 user authentication 177 user authentication, initializing 203 user input, backing up 216, 219 user menu 197 user, storing in centralized state 178 T text interpolation 12 U user interface animation, enhancing 85, 86 building 66 card list, animating 88 card, displaying 72, 74 card, playing 87 components, defining 68 components, using 68 content distribution, with slots 93, 95 CSS transitions 91 dynamic component 97, 99 game over overlay 96 gameplay data, adding to state 67 hand 78, 81 hand, animating with transitions 81, 84 key attribute 100 key special attribute 89 last play overlay 96 overlay animation 100 overlay background 101 overlays 92 parent-to-child communication, with Props 70 player turn overlay 95 props, using in template 71 top bar 67 user position, Google Maps about 266 centering, on user 267 user system, Geolocated Blog app Google OAuth, setting up 250, 251, 252 login button 252, 254 store, synchronizing with router 258 user, in store 254, 255 [ 374 ] user, store about 254 fetch plugin, adapting 256 profile picture, implementing 257 router, adapting 255 user session, checking on start 256, 257 V VNodes 275 Vue application about 126 babel Vue preset 131 babel, configuring 131 building, for production 134 creating 128 dependencies, updating 132 executing 129 polyfills 132 project, scaffolding 127 render functions 130 updating automatically 133 updating manually 133 vue package, updating 134 Vue instances Vue integration repository URL 368 Vue, features almighty components 66 app state 64 template option 63 Vue.js devtools references 10 Vue about compatibility requisites project setting up URL 6, Vuex modules about 261, 262 global elements, accessing 264 namespaced module 262, 263 ... [ vi ] 25 0 25 0 25 2 25 4 25 5 25 6 25 6 25 7 25 8 25 8 25 8 25 8 25 9 26 0 26 1 26 1 26 2 26 4 26 4 26 4 26 5 26 5 26 6 26 7 26 8 26 8 27 0 27 0 27 1 27 2 27 5 27 6 27 7 28 0 28 0 28 0 28 1 28 2 28 3 28 4 28 7 28 8 28 8 28 8 29 0 Table... helpers [v] 1 92 194 195 1 96 197 197 198 199 20 0 20 2 20 3 20 3 20 4 20 4 20 6 20 8 21 1 21 2 21 3 21 4 21 5 21 6 21 9 22 0 22 1 22 3 22 7 22 8 22 8 23 0 23 1 23 2 23 2 23 3 23 5 23 7 23 7 23 9 24 1 24 3 24 4 24 5 24 6 24 7 24 8 Table... [ vii ] 29 1 29 2 29 3 29 4 29 5 29 5 29 5 29 6 29 8 29 8 300 3 02 3 02 303 307 308 309 310 310 311 3 12 313 314 315 3 16 3 16 317 320 320 321 322 323 324 325 3 26 3 26 327 329 331 3 32 333 335 3 36 3 36 Table of