Remove old service architecture from Vue docs
This commit is contained in:
parent
0399b644ec
commit
5cb48d3686
Binary file not shown.
Before Width: | Height: | Size: 9.6 KiB |
|
@ -2,27 +2,24 @@
|
||||||
|
|
||||||
To get started with Vue, read through [their documentation][vue-docs].
|
To get started with Vue, read through [their documentation][vue-docs].
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
What is described in the following sections can be found in these examples:
|
||||||
|
|
||||||
|
- web ide: https://gitlab.com/gitlab-org/gitlab-ce/tree/master/app/assets/javascripts/ide/stores
|
||||||
|
- security products: https://gitlab.com/gitlab-org/gitlab-ee/tree/master/ee/app/assets/javascripts/vue_shared/security_reports
|
||||||
|
- registry: https://gitlab.com/gitlab-org/gitlab-ce/tree/master/app/assets/javascripts/registry/stores
|
||||||
|
|
||||||
## Vue architecture
|
## Vue architecture
|
||||||
|
|
||||||
All new features built with Vue.js must follow a [Flux architecture][flux].
|
All new features built with Vue.js must follow a [Flux architecture][flux].
|
||||||
The main goal we are trying to achieve is to have only one data flow and only one data entry.
|
The main goal we are trying to achieve is to have only one data flow and only one data entry.
|
||||||
In order to achieve this goal, you can either use [vuex](#vuex) or use the [store pattern][state-management], explained below:
|
In order to achieve this goal we use [vuex](#vuex).
|
||||||
|
|
||||||
Each Vue bundle needs a Store - where we keep all the data -, a Service - that we use to communicate with the server - and a main Vue component.
|
|
||||||
|
|
||||||
Think of the Main Vue Component as the entry point of your application. This is the only smart
|
|
||||||
component that should exist in each Vue feature.
|
|
||||||
This component is responsible for:
|
|
||||||
1. Calling the Service to get data from the server
|
|
||||||
1. Calling the Store to store the data received
|
|
||||||
1. Mounting all the other components
|
|
||||||
|
|
||||||
![Vue Architecture](img/vue_arch.png)
|
|
||||||
|
|
||||||
You can also read about this architecture in vue docs about [state management][state-management]
|
You can also read about this architecture in vue docs about [state management][state-management]
|
||||||
and about [one way data flow][one-way-data-flow].
|
and about [one way data flow][one-way-data-flow].
|
||||||
|
|
||||||
### Components, Stores and Services
|
### Components and Store
|
||||||
|
|
||||||
In some features implemented with Vue.js, like the [issue board][issue-boards]
|
In some features implemented with Vue.js, like the [issue board][issue-boards]
|
||||||
or [environments table][environments-table]
|
or [environments table][environments-table]
|
||||||
|
@ -33,10 +30,8 @@ new_feature
|
||||||
├── components
|
├── components
|
||||||
│ └── component.vue
|
│ └── component.vue
|
||||||
│ └── ...
|
│ └── ...
|
||||||
├── stores
|
├── store
|
||||||
│ └── new_feature_store.js
|
│ └── new_feature_store.js
|
||||||
├── services # only when not using vuex
|
|
||||||
│ └── new_feature_service.js
|
|
||||||
├── index.js
|
├── index.js
|
||||||
```
|
```
|
||||||
_For consistency purposes, we recommend you to follow the same structure._
|
_For consistency purposes, we recommend you to follow the same structure._
|
||||||
|
@ -125,217 +120,6 @@ You can read more about components in Vue.js site, [Component System][component-
|
||||||
#### Vuex
|
#### Vuex
|
||||||
Check this [page](vuex.md) for more details.
|
Check this [page](vuex.md) for more details.
|
||||||
|
|
||||||
#### Flux like state management
|
|
||||||
The Store is a class that allows us to manage the state in a single
|
|
||||||
source of truth. It is not aware of the service or the components.
|
|
||||||
|
|
||||||
The concept we are trying to follow is better explained by Vue documentation
|
|
||||||
itself, please read this guide: [State Management][state-management]
|
|
||||||
|
|
||||||
### A folder for the Service
|
|
||||||
|
|
||||||
**If you are using Vuex you won't need this step**
|
|
||||||
|
|
||||||
The Service is a class used only to communicate with the server.
|
|
||||||
It does not store or manipulate any data. It is not aware of the store or the components.
|
|
||||||
We use [axios][axios] to communicate with the server.
|
|
||||||
Refer to [axios](axios.md) for more details.
|
|
||||||
|
|
||||||
Axios instance should only be imported in the service file.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
import axios from '~/lib/utils/axios_utils';
|
|
||||||
```
|
|
||||||
|
|
||||||
### End Result
|
|
||||||
|
|
||||||
The following example shows an application:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// store.js
|
|
||||||
export default class Store {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is where we will iniatialize the state of our data.
|
|
||||||
* Usually in a small SPA you don't need any options when starting the store.
|
|
||||||
* In that case you do need guarantee it's an Object and it's documented.
|
|
||||||
*
|
|
||||||
* @param {Object} options
|
|
||||||
*/
|
|
||||||
constructor(options) {
|
|
||||||
this.options = options;
|
|
||||||
|
|
||||||
// Create a state object to handle all our data in the same place
|
|
||||||
this.todos = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
setTodos(todos = []) {
|
|
||||||
this.todos = todos;
|
|
||||||
}
|
|
||||||
|
|
||||||
addTodo(todo) {
|
|
||||||
this.todos.push(todo);
|
|
||||||
}
|
|
||||||
|
|
||||||
removeTodo(todoID) {
|
|
||||||
const state = this.todos;
|
|
||||||
|
|
||||||
const newState = state.filter((element) => {element.id !== todoID});
|
|
||||||
|
|
||||||
this.todos = newState;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// service.js
|
|
||||||
import axios from '~/lib/utils/axios_utils'
|
|
||||||
|
|
||||||
export default class Service {
|
|
||||||
constructor(options) {
|
|
||||||
this.todos = axios.create({
|
|
||||||
baseURL: endpoint.todosEndpoint
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
getTodos() {
|
|
||||||
return this.todos.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
addTodo(todo) {
|
|
||||||
return this.todos.put(todo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// todo_component.vue
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
data: {
|
|
||||||
type: Object,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<h1>
|
|
||||||
Title: {{data.title}}
|
|
||||||
</h1>
|
|
||||||
<p>
|
|
||||||
{{data.text}}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
// todos_main_component.vue
|
|
||||||
<script>
|
|
||||||
import Store from 'store';
|
|
||||||
import Service from 'service';
|
|
||||||
import TodoComponent from 'todoComponent';
|
|
||||||
export default {
|
|
||||||
components: {
|
|
||||||
todo: TodoComponent,
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Although most data belongs in the store, each component it's own state.
|
|
||||||
* We want to show a loading spinner while we are fetching the todos, this state belong
|
|
||||||
* in the component.
|
|
||||||
*
|
|
||||||
* We need to access the store methods through all methods of our component.
|
|
||||||
* We need to access the state of our store.
|
|
||||||
*/
|
|
||||||
data() {
|
|
||||||
const store = new Store();
|
|
||||||
|
|
||||||
return {
|
|
||||||
isLoading: false,
|
|
||||||
store: store,
|
|
||||||
todos: store.todos,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
created() {
|
|
||||||
this.service = new Service('/todos');
|
|
||||||
|
|
||||||
this.getTodos();
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
getTodos() {
|
|
||||||
this.isLoading = true;
|
|
||||||
|
|
||||||
this.service
|
|
||||||
.getTodos()
|
|
||||||
.then(response => {
|
|
||||||
this.store.setTodos(response);
|
|
||||||
this.isLoading = false;
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
this.isLoading = false;
|
|
||||||
// Show an error
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
addTodo(event) {
|
|
||||||
this.service
|
|
||||||
.addTodo({
|
|
||||||
title: 'New entry',
|
|
||||||
text: `You clicked on ${event.target.tagName}`,
|
|
||||||
})
|
|
||||||
.then(response => {
|
|
||||||
this.store.addTodo(response);
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
// Show an error
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
<template>
|
|
||||||
<div class="container">
|
|
||||||
<div v-if="isLoading">
|
|
||||||
<i
|
|
||||||
class="fa fa-spin fa-spinner"
|
|
||||||
aria-hidden="true" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
v-if="!isLoading"
|
|
||||||
class="js-todo-list">
|
|
||||||
<template v-for='todo in todos'>
|
|
||||||
<todo :data="todo" />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<button
|
|
||||||
@click="addTodo"
|
|
||||||
class="js-add-todo">
|
|
||||||
Add Todo
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
// index.js
|
|
||||||
import todoComponent from 'todos_main_component.vue';
|
|
||||||
|
|
||||||
new Vue({
|
|
||||||
el: '.js-todo-app',
|
|
||||||
components: {
|
|
||||||
todoComponent,
|
|
||||||
},
|
|
||||||
render: createElement => createElement('todo-component' {
|
|
||||||
props: {
|
|
||||||
someProp: [],
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
The [issue boards service][issue-boards-service]
|
|
||||||
is a good example of this pattern.
|
|
||||||
|
|
||||||
## Style guide
|
## Style guide
|
||||||
|
|
||||||
Please refer to the Vue section of our [style guide](style_guide_js.md#vue-js)
|
Please refer to the Vue section of our [style guide](style_guide_js.md#vue-js)
|
||||||
|
@ -446,6 +230,5 @@ need to test the rendered output. [Vue][vue-test] guide's to unit test show us e
|
||||||
[state-management]: https://vuejs.org/v2/guide/state-management.html#Simple-State-Management-from-Scratch
|
[state-management]: https://vuejs.org/v2/guide/state-management.html#Simple-State-Management-from-Scratch
|
||||||
[one-way-data-flow]: https://vuejs.org/v2/guide/components.html#One-Way-Data-Flow
|
[one-way-data-flow]: https://vuejs.org/v2/guide/components.html#One-Way-Data-Flow
|
||||||
[vue-test]: https://vuejs.org/v2/guide/unit-testing.html
|
[vue-test]: https://vuejs.org/v2/guide/unit-testing.html
|
||||||
[issue-boards-service]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/app/assets/javascripts/boards/services/board_service.js.es6
|
|
||||||
[flux]: https://facebook.github.io/flux
|
[flux]: https://facebook.github.io/flux
|
||||||
[axios]: https://github.com/axios/axios
|
[axios]: https://github.com/axios/axios
|
||||||
|
|
Loading…
Reference in New Issue