Setting up an online store with Flask and Vue
Tags: flask, vue, webdev, tutorial
Published: 2020-01-23 14:36:42

---
title: Setting up an online store with Flask and Vue
published: true
date: 2020-01-21 17:00:54 UTC
tags: flask,vue,webdev,tutorial 
canonical_url: https://blog.logrocket.com/setting-up-an-online-store-with-flask-and-vue/
cover_image: https://thepracticaldev.s3.amazonaws.com/i/968cyq4fpxbjlqq2c793.png
---
**Written by [Raphael Ugwu](https://blog.logrocket.com/author/raphaelugwu/)**✏️

In this tutorial, we’ll learn how to build an e-commerce store with [Vue](https://vuejs.org/) and [Flask](http://flask.palletsprojects.com/en/1.1.x/) (a micro web framework written in Python). Our store will be able to create, read, update, and delete content via a server-side RESTful API powered by Flask.

## App requirements

If you have basic knowledge of Vue and Python and want to learn how to build cool stuff across a range of frameworks then this is a good place to get started. Our application will rely on the following frameworks and libraries as major dependencies:

- [`Vue`](https://vuejs.org/): A progressive framework used for building user interfaces
- [`Vue CLI`](https://cli.vuejs.org/): Vue’s command line interface which provides a robust system for rapid Vue JS development
- [`Node`](https://nodejs.org/en/): JavaScript’s runtime environment that executes JavaScript code outside the browser
- [`npm`](https://www.npmjs.com/): The default package manager for JavaScript’s runtime environment, NodeJS
- [`Flask`](http://flask.palletsprojects.com/en/1.1.x/): A micro web framework written in Python
- [`Python`](https://www.python.org/): A general-purpose programming language used to develop a wide range of applications
- [`virtualenv`](https://docs.python.org/3/library/venv.html): A module that creates virtual environments in Python and its related frameworks

The first thing you should check for is if you have Python and virutalenv installed on your machine. If not, you can learn more about these here:

- [Install Python 3 for all OS types](https://realpython.com/installing-python/)
- [Install virtualenv](https://virtualenv.pypa.io/en/latest/installation/)

[![LogRocket Free Trial Banner](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2017/03/f760c-1gpjapknnuyhu8esa3z0jga.png?resize=1200%2C280&ssl=1)](https://logrocket.com/signup/)

## Setting up Flask

Before installing Flask, we’ll first create our project directory via our terminal:

```jsx
$ mkdir vue-flask-store
$ cd vue-flask-store
```

In `vue-flask-store`, create a new directory, name it `server`. Then with the virtualenv’s `venv` command, create a virtual environment in `vue-flask-store` :

```jsx
$ python3.7 -m venv env
$ source env/bin/activate
```

Now, install Flask along with the [Flask-CORS](https://flask-cors.readthedocs.io/en/latest/) extension which will assist us in handling cross-origin requests:

```jsx
(env)$ pip install Flask Flask-Cors
```

When done with the installation, you should have a folder structure similar to this:

```jsx
├── VUE-FLASK-STORE
└── env
    ├── bin
    ├── include
    ├── lib / python 3.7 / site-packages
    ├── pyvenv.cfg
└── server    (env)$ pip install Flask Flask-Cors
```

## Setting up Vue

We’ll create a Vue project by using Vue CLI. Navigate to your terminal and install it globally:

```jsx
$ npm install -g @vue/cli
```

Then, still in the terminal, navigate to the `vue-flask-store` project and initialize a new Vue project which we’ll call `frontend`. When prompted to choose from an array of options, follow the format below:

```jsx
Vue CLI v3.7.0
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, Router, Linter
? Use history mode for router? Yes
? Pick a linter / formatter config: Airbnb
? Pick additional lint features: Lint on save
? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? In package.json
? Save this as a preset for future projects? (y/N) No
```

When we’re done, we’ll have a generated Vue project with a folder structure similar to this:

```jsx
├── VUE-FLASK-STORE
└── frontend
    └── public
       ├── index.html
    └── src
       └── assets
          ├── logo.png
       └── components
          ├── HelloWorld.vue
       └── router
          ├── index.js
       ├── App.vue
       ├── main.js

    ├── .editorconfig
    ├── .gitignore
    ├── .babel.config.js
    ├── package-lock.json
    ├── package.json
└── server
```

In your terminal, navigate to `frontend` and start the development server:

```jsx
$ cd client
$ npm run serve
```

Then on your browser, navigate to [`http://localhost:8080`](http://localhost:8080/). You should see a page similar to this:

![](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2020/01/vuepage.png?resize=1396%2C1540&ssl=1)

To connect the requests we’ll be making on the frontend (our Vue app), to the backend (our Flask app), we’ll need to include the [`axios`](https://www.npmjs.com/package/axios) library in our project. Still in your terminal, install `axios` in the `frontend` folder:

```jsx
$ npm install axios --save
```

Lastly for some styling, we’ll include `bootstrap-vue` (an implementation of Bootstrap for VueJS). We’ll install `bootstrap-vue` just the same way `axios` was installed:

```jsx
$ npm install bootstrap-vue --save
```

Then enable it by importing it in `frontend/src/main.js`:

```jsx
// frontend/src/main.js

import BootstrapVue from "bootstrap-vue";
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
Vue.use(BootstrapVue);
Vue.config.productionTip = false;
new Vue({
  router,
  render: h => h(App)
}).$mount("#app");
```

At this point we have all the dependencies we need, we can then go on to build all the routes that will make up our app.

## Building the application

When we’re done building our app it should look similar to this:

{% youtube g7Az3cEhVjU %}

We want to build an e-commerce store that has JavaScript courses. A user should be able to perform the following operations:

- Select if they want the paperback version of a course or not
- Delete a course from the list of courses
- Add a course they want to purchase but is not on the default list (which we’ll create in our Flask server)

## Creating a server in Flask

The first step would be to create a server in our Flask app. This would contain the default list of courses on our app as well as handles for any routes on the app that our users may want to take. Navigate to the `server` folder in your Flask app and create a file named `app.py` , the first thing we’ll do in `app.py` is to add the default list of courses:

```jsx
// server/app.py

COURSES = [
    {
        'title': 'Effective JavaScript: 68 Specific Ways to Harness the Power of JavaScript ',
        'author': 'David Herman',
        'paperback': True
    },
    {
        'title': 'JavaScript: The Good Parts',
        'author': 'Douglas Crockford',
        'paperback': False    
    },
    {
        'title': 'Eloquent JavaScript: A Modern Introduction to Programming',
        'author': 'Marijn Haverbeke',
        'paperback': True
    }
]        
```

Then we’ll add a route handler that routes back to this list:

```jsx
from flask import Flask, jsonify

@app.route('/courses', methods=['GET'])
def all_courses():
    return jsonify({
        'status': 'success',
        'courses': COURSES
    })
```

Head on to your terminal and run the Flask app (in your virtual environment) by inputting the command below:

```jsx
(env) server % python app.py
```

On your browser, test out the route at [http://localhost:5000/courses](http://localhost:5000/courses). You should see a page similar to this:

![localhost courses](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2020/01/s_DCF528C5644AE0916E7F659A59D8A90887EEC0BF4F070DB04B1D5792D0636D16_1579204194064_image_preview10.png?resize=730%2C431&ssl=1)

## Updating the Vue app

Having created a server, the next step is to update our frontend with its content. In the `src/components` folder of your Vue app, create a file named `Courses.vue` . Here, we’ll create a template styled by classes from `bootstrap-vue`. We’ll use [Vue directives](https://vuejs.org/v2/guide/custom-directive.html) as well to handle some logic:

```jsx
<!-- src/components/Courses.vue -->

    <template>
      <div class="container">
          <h1>Courses</h1>
            <hr>
            <button type="button" class="btn btn-success btn-sm">Add Course</button>
            <table class="table table-hover">
                <tr>
                  <th scope="col">Title</th>
                  <th scope="col">Author</th>
                  <th scope="col">Paperback</th>
                </tr>
              <tbody>
                <tr v-for="(course, index) in courses" :key="index">
                  <td>{{ course.title }}</td>
                  <td>{{ course.author }}</td>
                  <td>
                    <span v-if="course.paperback">Yes</span>
                    <span v-else>No</span>
                  </td>
                  <td>
                  <button type="button" class="btn btn-info btn-sm">Update</button>
                  <button type="button" class="btn btn-danger btn-sm">Delete</button>
                  </td>
                </tr>
              </tbody>
            </table>
      </div>
    </template>
```

In the template, `v-for` is used to iterate through the list of courses using the `index` value as a key. Then `v-if` is used to render `Yes` or `No` options to indicate if a user wants the course in paperback or not.

In the `script` section of our component, we’ll create a method called `getCourses()` where we’ll use `axios` to make a `GET` request to our server. We’ll then use Vue’s `created` lifecycle hook to fetch our courses from the server we built with Flask:

```jsx
<!-- src/components/Courses.vue -->

 <script>
 import axios from 'axios';
 export default {
  data() {
    return {
      courses: [],
    };
  },
  methods: {
    getCourses() {
      const path = 'http://localhost:5000/courses';
      axios.get(path)
        .then((res) => {
          this.courses = res.data.courses;
        })
        .catch((error) => {
          console.error(error);
        });
    },
  },
  created() {
    this.getCourses();
  },
 };
 </script>
```

There, save `Course.vue` and in your terminal, run `npm run serve`. You should have an interface that is closely similar to this:

![course vue](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2020/01/coursevue.png?resize=730%2C456&ssl=1)

Notice we explained everything except the `Add Course` button. We’ll handle that in the next section where we’ll learn how to modify our server and frontend to handle requests to add new courses from our users.

## Modifying the server for POST requests

For a user to add a course to the already existing list of courses, a `POST` request has to be sent to the server. Let’s modify `server/app.py` to accept these requests. In `app.py`, update the existing route handler `all_courses` to handle `POST` requests for adding a new course:

```jsx
from flask import Flask, jsonify, request

@app.route('/courses', methods=['GET', 'POST'])
def all_courses():
    response_object = {'status': 'success'}
    if request.method == 'POST':
        post_data = request.get_json()
        COURSES.append({
            'title': post_data.get('title'),
            'author': post_data.get('author'),
            'paperback': post_data.get('paperback')
        })
        response_object['message'] = 'Course added!'
    else:
        response_object['courses'] = COURSES
    return jsonify(response_object)
```

Next, in the `Courses` component we’ll add a modal to our frontend to enable users to add courses to the default list:

```jsx
<!-- src/components/Courses.vue -->

<template>
<b-modal ref="addCourseModal"
         id="course-modal"
         title="Add a new course"
         hide-footer>
  <b-form @submit="onSubmit" @reset="onReset" class="w-100">
  <b-form-group id="form-title-group"
                label="Title:"
                label-for="form-title-input">
      <b-form-input id="form-title-input"
                    type="text"
                    v-model="addCourseForm.title"
                    required
                    placeholder="Enter title">
      </b-form-input>
    </b-form-group>
    <b-form-group id="form-author-group"
                  label="Author:"
                  label-for="form-author-input">
        <b-form-input id="form-author-input"
                      type="text"
                      v-model="addCourseForm.author"
                      required
                      placeholder="Enter author">
        </b-form-input>
      </b-form-group>
    <b-form-group id="form-read-group">
      <b-form-checkbox-group v-model="addCourseForm.paperback" id="form-checks">
        <b-form-checkbox value="true">Paperback</b-form-checkbox>
      </b-form-checkbox-group>
    </b-form-group>
    <b-button type="submit" variant="primary">Submit</b-button>
    <b-button type="reset" variant="danger">Reset</b-button>
  </b-form>
</b-modal>
</template>
```

In the code sample above, we created a modal and used the `v-model` directive to attach any values a user will input back to our app’s state. Let’s update our `script` section to include the state `addCourseForm` which is bound to user input via the `v-model` directive. When a user updates the input, this state gets updated as well:

```jsx
<!-- src/components/Courses.vue -->

<script>
import axios from 'axios';
export default {
  data() {
    return {
      courses: [],
      addCourseForm: {
        title: '',
        author: '',
        paperback: [],
      },
    };
  },
  created() {
    this.getCourses();
  },
};
</script>
```

Then we’ll create different methods to handle each action a user performs. Below is a couple of methods we’ll be creating and how they’ll assist in handling each of our actions:

- `addCourse`: This method sends a POST request to `/courses` to include a new course to the existing list of courses
- `initForm`: This method appends every detail of the course that’s to be added to `addCourseForm`
- `onSubmit`: This method executes when a user adds a course successfully. First, default browser behavior is prevented via `e.preventDefault()`, then the modal used to add the form is closed successfully with `this.refs.addCourseModal.hide()`, the `addCourse` method is executed and the form is reinitialized and cleared with `initForm()`

```jsx
// src/components/Courses.vue

methods: {
   addCourse(payload) {
     const path = "http://localhost:5000/courses";
     axios
       .post(path, payload)
       .then(() => {
         this.getCourses();
       })
       .catch(error => {
         // eslint-disable-next-line
         console.log(error);
         this.getCourses();
       });
   },
   initForm() {
     this.addCourseForm.title = "";
     this.addCourseForm.author = "";
     this.addCourseForm.paperback = [];
   },
   onSubmit(e) {
     e.preventDefault();
     this.$refs.addCourseModal.hide();
     let paperback = false;
     if (this.addCourseForm.paperback[0]) paperback = true;
     const payload = {
       title: this.addCourseForm.title,
       author: this.addCourseForm.author,
       paperback
     };
     this.addCourse(payload);
     this.initForm();
   }
 }
```

When we’re done, let’s update the `Add Course` button in our template so that the modal will be displayed when the button is clicked:

```jsx
<!-- src/components/Courses.vue -->

<template>
  <button type="button" class="btn btn-success btn-sm" v-b-modal.course-modal>
    Add Course
  </button>
</template>
```

Now, let’s try to add a course and see what happens:

{% youtube zyWQcVIFaxE %}

## Adding an alert component

It would be nice for our users to have some sort of alert or popup whenever an action occurs like when a course is added, updated, or deleted. To include an alert for our app, let’s begin by creating a new component which we’ll call `Alert.vue`. In this component, we’ll use `b-alert`, an inbuilt component of `bootstrap-vue`, to display the message we want to show when an alert pops up:

```jsx
<!-- src/components/Alert.vue -->

<template>
  <div>
    <b-alert variant="success" show>{{ message }}</b-alert>
    <br />
  </div>
</template>

<script>
export default {
  props: ["message"]
};
</script>
```

At this point, you may be wondering what’s going on here. We specified a `message` prop which can receive updates from the `Courses` component as that’s where we’ll export and handle the `Alert` component. In `Courses.vue`, import the `Alert` component and add the `message` prop to the `data()` object:

```jsx
<!-- src/components/Courses.vue -->

<script>
import Alert from "./Alert.vue";
export default {
  data() {
    return {
      courses: [],
      addCourseForm: {
        title: "",
        author: "",
        paperback: []
      },
       message: "",
    };
  }
};
</script>
```

Next, in the `addCourse` method, we’ll update the message with what we need:

```jsx
<!-- src/components/Courses.vue -->
...
  addCourse(payload) {
    const path = 'http://localhost:5000/courses';
    axios.post(path, payload)
      .then(() => {
        this.getCourses();
        this.message = 'Course added!';
      })
      .catch((error) => {
        console.log(error);
        this.getCourses();
      });
  }
...
```

In the `data()` object, we’ll include another property `showMessage` which will decide if an alert should be displayed or not, based on if a course has been added or not. `showMessage` will have an initial boolean value of `false`:

```jsx
<!-- src/components/Courses.vue -->

<script>
import Alert from "./Alert.vue";
export default {
  data() {
    return {
      courses: [],
      addCourseForm: {
        title: "",
        author: "",
        paperback: []
      },
       message: "",
       showMessage: false,
    };
  }
};
</script>
```

Then in our template, we’ll update the `Alert` component with a `v-if` directive which conditionally renders `Alert` based on either of the two values – `true` or `false`:

```jsx
<!-- src/components/Courses.vue -->

<template>
  <button>
    <alert :message=message v-if="showMessage"></alert>
  </button>
</template>
```

Lastly, we’ll update the `AddCourse` method and set `showMessage` to true whenever a course is successfully added:

```jsx
<!-- src/components/Courses.vue -->
<script>
import Alert from "./Alert.vue";
export default {
  methods: {
    addCourse(payload) {
      const path = "http://localhost:5000/courses";
      axios
        .post(path, payload)
        .then(() => {
          this.getCourses();
          this.message = "Course added!";
          this.showMessage = true;
        })
        .catch(error => {
          console.log(error);
          this.getCourses();
        });
    }
  }
};
</script>
```

Now, let’s see if our alert will be displayed. Save your work, run `npm run serve` on your terminal and go to your browser:

{% youtube bZJi2OmGSvg %}

## Setting up unique identifiers

We may have a situation where two courses have exactly the same name. To handle this, we need each update our users make to have a unique identifier. To achieve this, we’ll use `uuid`, a module in Python’s library that provides unique IDs. Let’s update our server so all our default courses have random IDs:

```jsx
# server/app.py

from flask import Flask, jsonify, request
import uuid

COURSES = [
   {
       'id': uuid.uuid4().hex,
       'title': 'Effective JavaScript: 68 Specific Ways to Harness the Power of JavaScript ',
       'author': 'David Herman',
       'paperback': True
   },
   {
       'id': uuid.uuid4().hex,
       'title': 'JavaScript: The Good Parts',
       'author': 'Douglas Crockford',
       'paperback': False
   },
   {
       'id': uuid.uuid4().hex,
       'title': 'Eloquent JavaScript: A Modern Introduction to Programming',
       'author': 'Marijn Haverbeke',
       'paperback': True
   }
]
```

Next, we’ll configure `all_courses` to process the random IDs each time a user adds a new course:

```jsx
@app.route('/courses', methods=['GET', 'POST'])
def all_courses():
    response_object = {'status': 'success'}
    if request.method == 'POST':
        post_data = request.get_json()
        COURSES.append({
            'id': uuid.uuid4().hex,
            'title': post_data.get('title'),
            'author': post_data.get('author'),
            'paperback': post_data.get('paperback'),
                })
        response_object['message'] = 'Course added!'
    else:
        response_object['courses'] = COURSES
    return jsonify(response_object)
```

## Updating existing courses

Suppose our users want to make changes to courses that exist on our app, we can make this possible by creating another modal in `Courses.vue` to handle this. In `Courses.vue`, create another modal called `editCourseModal` just below `addCourseModal`. We’ll wrap all the properties of the form we want to create under `b-form` which is a form element provided by `bootstrap-vue`. The first property we’ll create an input for is the title of the course. Here we can modify the title to what we want:

```jsx
<b-form-group  id="form-title-edit-group"  label="Title:"
             label-for="form-title-edit-input"
>
    <b-form-input  id="form-title-edit-input"  type="text"
        v-model="editForm.title"
        required
        placeholder="Enter title"
    >
    </b-form-input>
</b-form-group>
```

Next, we’ll create an input field for where we can update the name of the author:

```jsx
<b-form-group id="form-author-edit-group"  label="Author:"
  label-for="form-author-edit-input"
>
    <b-form-input  id="form-author-edit-input"  type="text"
        v-model="editForm.author"
        required
        placeholder="Enter author"
    >
    </b-form-input>
</b-form-group>
```

Then we’ll create a checkbox, where the user can have the option of modifying if the course should be in paperback or not:

```jsx
<b-form-group id="form-read-edit-group">
    <b-form-checkbox-group v-model="editForm.paperback" id="form-checks">
        <b-form-checkbox value="true">Paperback</b-form-checkbox>
    </b-form-checkbox-group>
</b-form-group>
```

Then we’ll create two buttons – `Update` to update the changes we’ve made and `Cancel` to close the modal if we no longer want to make the changes:

```jsx
<b-button-group>
    <b-button type="submit" variant="primary">Update</b-button>
    <b-button type="reset" variant="danger">Cancel</b-button>
</b-button-group>
```

Finally, we’ll wrap all the elements we just created in the `b-form` element:

```jsx
<template>
    <b-modal ref="editCourseModal" id="course-update-modal" title="Update">
        <b-form @submit="onSubmitUpdate" @reset="onResetUpdate" class="w-100"  

            <!--Place all the elements here-->

        </b-form>
    </b-modal>
</template>
```

Next, in the `script` tag of `Courses.vue`, we’ll update the state of this modal:

```jsx
<!-- src/components/Courses.vue -->

<script>
import Alert from "./Alert.vue";
export default {
  data() {
    return {
      courses: [],
      addCourseForm: {
        title: "",
        author: "",
        paperback: []
      },
      editForm: {
        id: "",
        title: "",
        author: "",
        paperback: []
      },
      message: "",
      showMessage: false
    };
  }
};
</script>
```

Next, we’ll modify the `Update` and `Cancel` buttons to make updates to a course or delete a course off the list. First, for the `Update` button, we’ll create a method to update the values in `editForm`:

```jsx
<!-- src/components/Courses.vue -->

<script>
import Alert from "./Alert.vue";
export default {

    methods: {
      editCourse(course) {
      this.editForm = course;
    },
  }

};
</script>
```

Next, we’ll create a method to handle the submitting of the form containing the updated details:

```jsx
<!-- src/components/Courses.vue -->

<script>
import Alert from "./Alert.vue";
export default {
  methods: {
    editCourse(course) {
      this.editForm = course;
    },
    onSubmitUpdate(e) {
      e.preventDefault();
      this.$refs.editCourseModal.hide();
      let paperback = false;
      if (this.editForm.paperback[0]) paperback = true;
      const payload = {
        title: this.editForm.title,
        author: this.editForm.author,
        paperback
      };
      this.updateBook(payload, this.editForm.id);
    }
  }
};
</script>
```

Then we’ll use `axios` to make a request to update our server. We’ll also include a message that will display as an alert each time a book is added:

```jsx
<!-- src/components/Courses.vue -->

<script>
import Alert from "./Alert.vue";
export default {
  methods: {
    updateCourse(payload, courseID) {
      const path = `http://localhost:5000/courses/${courseID}`;
      axios
        .put(path, payload)
        .then(() => {
          this.getCourses();
          this.message = 'Course updated!';
          this.showMessage = true;
        })
        .catch(error => {
          console.error(error);
          this.getCourses();
        });
    }
  }
};
</script>
```

To cancel an update, we’ll create a method that closes the `editForm` modal, reinitializes the form and makes a request to get the current list of courses:

```jsx
<!-- src/components/Courses.vue -->

<script>
import Alert from "./Alert.vue";
export default {
  methods: {
    onResetUpdate(evt) {
      evt.preventDefault();
      this.$refs.editBookModal.hide();
      this.initForm();
      this.getBooks();
    }
  }
};
</script>
```

Then we’ll update `initForm` to include properties of `editForm` as well:

```jsx
<!-- src/components/Courses.vue -->
<script>
import Alert from "./Alert.vue";
export default {
  methods: {
    initForm() {
      this.addBookForm.title = "";
      this.addBookForm.author = "";
      this.addBookForm.read = [];
      this.editForm.id = "";
      this.editForm.title = "";
      this.editForm.author = "";
      this.editForm.read = [];
    }
  }
};
</script>
```

There. Now let’s see if our updates and changes work:

{% youtube iJ_bbLJ9CfA %}

## Deleting existing courses

To delete an existing course from the list of courses, we’ll create a method in the `script` section of `Courses.vue`. Our method should be able to make a `delete` request via `axios` to delete a course by its ID, get the current list of courses, and display an alert that says the course has been deleted:

```jsx
<!-- src/components/Courses.vue -->
<script>
import Alert from "./Alert.vue";
export default {
  methods: {
    removeCourse(courseID) {
      const path = `http://localhost:5000/courses/${courseID}`;
      axios
        .delete(path)
        .then(() => {
          this.getCourses();
          this.message = " Course removed!";
          this.showMessage = true;
        })
        .catch(error => {
          console.error(error);
          this.getCourses();
        });
    },
    onDeleteCourse(course) {
      this.removeCourse(course.id);
    }
  }
};
</script>
```

Let’s review how this works:

{% youtube 17a769UYroM %}

## Conclusion

Frameworks were built to give developers more leverage and functionality with programming languages. Thankfully we’ve been able to show how awesome this leverage could be if it is used right. Readers are encouraged to go further and improve on this – add a shopping cart, images, or a payment method maybe. You can check out the full code of this project [here on GitHub](https://github.com/fullstackmafia/vue-flask-js-store).

* * *
## Experience your Vue apps exactly how a user does 

Debugging Vue.js applications can be difficult, especially when there are dozens, if not hundreds of mutations during a user session. If you’re interested in monitoring and tracking Vue mutations for all of your users in production, [try LogRocket.](https://www2.logrocket.com/vue-performance-monitoring)

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/t4ni6gomxqbkbxygmco0.png)

[LogRocket](https://www2.logrocket.com/vue-performance-monitoring) is like a DVR for web apps, recording literally everything that happens in your Vue apps including network requests, JavaScript errors, performance problems, and much more. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred.

The LogRocket Vuex plugin logs Vuex mutations to the LogRocket console, giving you context around what led to an error, and what state the application was in when an issue occurred.

Modernize how you debug your Vue apps - [Start monitoring for free.](https://www2.logrocket.com/vue-performance-monitoring)
* * *

The post [Setting up an online store with Flask and Vue](https://blog.logrocket.com/setting-up-an-online-store-with-flask-and-vue/) appeared first on [LogRocket Blog](https://blog.logrocket.com).