From c7b3ba834b80d81521a7e6619276e0920d4af94c Mon Sep 17 00:00:00 2001 From: Filipa Lacerda <filipa@gitlab.com> Date: Thu, 20 Apr 2017 11:24:40 +0000 Subject: [PATCH] Adds vue js example application and documentation --- .../fe_guide/img/boards_diagram.png | Bin 0 -> 30538 bytes doc/development/fe_guide/img/vue_arch.png | Bin 0 -> 9848 bytes doc/development/fe_guide/index.md | 53 +++ doc/development/fe_guide/style_guide_js.md | 23 +- doc/development/fe_guide/testing.md | 5 + doc/development/fe_guide/vue.md | 343 +++++++++++++++++- 6 files changed, 408 insertions(+), 16 deletions(-) create mode 100644 doc/development/fe_guide/img/boards_diagram.png create mode 100644 doc/development/fe_guide/img/vue_arch.png diff --git a/doc/development/fe_guide/img/boards_diagram.png b/doc/development/fe_guide/img/boards_diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..7a2cf972fd019fdf8593a84eaf4f6b6b6ceca689 GIT binary patch literal 30538 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 A@c;k- literal 0 HcmV?d00001 diff --git a/doc/development/fe_guide/img/vue_arch.png b/doc/development/fe_guide/img/vue_arch.png new file mode 100644 index 0000000000000000000000000000000000000000..a67706c7c1e5dce1491e92c576f95d6d8911f4ec GIT binary patch literal 9848 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 A@c;k- literal 0 HcmV?d00001 diff --git a/doc/development/fe_guide/index.md b/doc/development/fe_guide/index.md index c7d4f2e9c23..e2a198f637f 100644 --- a/doc/development/fe_guide/index.md +++ b/doc/development/fe_guide/index.md @@ -25,6 +25,59 @@ Working with our frontend assets requires Node (v4.3 or greater) and Yarn For our currently-supported browsers, see our [requirements][requirements]. +--- + +## Development Process + +When you are assigned an issue please follow the next steps: + +### Divide a big feature into small Merge Requests +1. Big Merge Request are painful to review. In order to make this process easier we +must break a big feature into smaller ones and create a Merge Request for each step. +1. First step is to create a branch from `master`, let's call it `new-feature`. This branch +will be the recipient of all the smaller Merge Requests. Only this one will be merged to master. +1. Don't do any work on this one, let's keep it synced with master. +1. Create a new branch from `new-feature`, let's call it `new-feature-step-1`. We advise you +to clearly identify which step the branch represents. +1. Do the first part of the modifications in this branch. The target branch of this Merge Request +should be `new-feature`. +1. Once `new-feature-step-1` gets merged into `new-feature` we can continue our work. Create a new +branch from `new-feature`, let's call it `new-feature-step-2` and repeat the process done before. + +```shell +* master +|\ +| * new-feature +| |\ +| | * new-feature-step-1 +| |\ +| | * new-feature-step-2 +| |\ +| | * new-feature-step-3 +``` + +**Tips** +- Make sure `new-feature` branch is always synced with `master`: merge master frequently. +- Do the same for the feature branch you have opened. This can be accomplished by merging `master` into `new-feature` and `new-feature` into `new-feature-step-*` +- Avoid rewriting history. + +### Share your work early +1. Before writing code guarantee your vision of the architecture is aligned with +GitLab's architecture. +1. Add a diagram to the issue and ask a Frontend Architecture about it. + +  + +1. Don't take more than one week between starting work on a feature and +sharing a Merge Request with a reviewer or a maintainer. + +### Vue features +1. Follow the steps in [Vue.js Best Practices](vue.md) +1. Follow the style guide. +1. Only a handful of people are allowed to merge Vue related features. +Reach out to @jschatz, @iamphill, @fatihacet or @filipa early in this process. + + --- ## [Architecture](architecture.md) diff --git a/doc/development/fe_guide/style_guide_js.md b/doc/development/fe_guide/style_guide_js.md index abd241c0bc8..ed656476a96 100644 --- a/doc/development/fe_guide/style_guide_js.md +++ b/doc/development/fe_guide/style_guide_js.md @@ -58,7 +58,7 @@ See [our current .eslintrc][eslintrc] for specific rules and patterns. import Bar from './bar'; ``` -- **Never** disable the `no-undef` rule. Declare globals with `/* global Foo */` instead. +- **Never** disable the `no-undef` rule. Declare globals with `/* global Foo */` instead. - When declaring multiple globals, always use one `/* global [name] */` line per variable. @@ -183,6 +183,19 @@ See [our current .eslintrc][eslintrc] for specific rules and patterns. parseInt('10', 10); ``` +#### CSS classes used for JavaScript +- If the class is being used in Javascript it needs to be prepend with `js-` + ```html + // bad + <button class="add-user"> + Add User + </button> + + // good + <button class="js-add-user"> + Add User + </button> + ``` ### Vue.js @@ -200,6 +213,7 @@ See [our current .eslintrc][eslintrc] for specific rules and patterns. #### Naming - **Extensions**: Use `.vue` extension for Vue components. - **Reference Naming**: Use PascalCase for Vue components and camelCase for their instances: + ```javascript // bad import cardBoard from 'cardBoard'; @@ -217,6 +231,7 @@ See [our current .eslintrc][eslintrc] for specific rules and patterns. cardBoard: CardBoard }; ``` + - **Props Naming:** - Avoid using DOM component prop names. - Use kebab-case instead of camelCase to provide props in templates. @@ -243,12 +258,18 @@ See [our current .eslintrc][eslintrc] for specific rules and patterns. <component v-if="bar" param="baz" /> + <button class="btn">Click me</button> + // good <component v-if="bar" param="baz" /> + <button class="btn"> + Click me + </button> + // if props fit in one line then keep it on the same line <component bar="bar" /> ``` diff --git a/doc/development/fe_guide/testing.md b/doc/development/fe_guide/testing.md index a4631fd0073..66afbf4db4d 100644 --- a/doc/development/fe_guide/testing.md +++ b/doc/development/fe_guide/testing.md @@ -26,6 +26,10 @@ browser and you will not have access to certain APIs, such as [`Notification`](https://developer.mozilla.org/en-US/docs/Web/API/notification), which will have to be stubbed. +### Writing tests +### Vue.js unit tests +See this [section][vue-test]. + ### Running frontend tests `rake karma` runs the frontend-only (JavaScript) tests. @@ -134,3 +138,4 @@ Scenario: Developer can approve merge request [jasmine-focus]: https://jasmine.github.io/2.5/focused_specs.html [jasmine-jquery]: https://github.com/velesin/jasmine-jquery [karma]: http://karma-runner.github.io/ +[vue-test]:https://docs.gitlab.com/ce/development/fe_guide/vue.html#testing-vue-components diff --git a/doc/development/fe_guide/vue.md b/doc/development/fe_guide/vue.md index 3e3406e7d6a..45c8300d9de 100644 --- a/doc/development/fe_guide/vue.md +++ b/doc/development/fe_guide/vue.md @@ -19,13 +19,31 @@ We don't want to refactor all GitLab frontend code into Vue.js, here are some gu when not to use Vue.js: - Adding or changing static information; -- Features that highly depend on jQuery will be hard to work with Vue.js +- Features that highly depend on jQuery will be hard to work with Vue.js; +- Features without reactive data; As always, the Frontend Architectural Experts are available to help with any Vue or JavaScript questions. -## How to build a new feature with Vue.js +## Vue architecture -**Components, Stores and Services** +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. +In order to achieve this goal, 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 + +  + +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]. + +### Components, Stores and Services In some features implemented with Vue.js, like the [issue board][issue-boards] or [environments table][environments-table] @@ -46,16 +64,17 @@ _For consistency purposes, we recommend you to follow the same structure._ Let's look into each of them: -**A `*_bundle.js` file** +### A `*_bundle.js` file This is the index file of your new feature. This is where the root Vue instance of the new feature should be. -The Store and the Service should be imported and initialized in this file and provided as a prop to the main component. +The Store and the Service should be imported and initialized in this file and +provided as a prop to the main component. Don't forget to follow [these steps.][page_specific_javascript] -**A folder for Components** +### A folder for Components This folder holds all components that are specific of this new feature. If you need to use or create a component that will probably be used somewhere @@ -70,29 +89,320 @@ in one table would not be a good use of this pattern. You can read more about components in Vue.js site, [Component System][component-system] -**A folder for the Store** +### A folder for the Store The Store is a class that allows us to manage the state in a single -source of truth. +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** +### A folder for the Service + +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 [vue-resource][vue-resource-repo] to communicate with the server. + +### 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 the 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 Vue from 'vue'; +import VueResource from 'vue-resource'; +import 'vue_shared/vue_resource_interceptor'; + +Vue.use(VueResource); + +export default class Service { + constructor(options) { + this.todos = Vue.resource(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 { + /** + * 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, + }; + }, + + components: { + todo: TodoComponent, + }, + + created() { + this.service = new Service('todos'); + + this.getTodos(); + }, + + methods: { + getTodos() { + this.isLoading = true; + + this.service.getTodos() + .then(response => response.json()) + .then((response) => { + this.store.setTodos(response); + this.isLoading = false; + }) + .catch(() => { + this.isLoading = false; + // Show an error + }); + }, + + addTodo(todo) { + this.service.addTodo(todo) + then(response => response.json()) + .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> + +// bundle.js +import todoComponent from 'todos_main_component.vue'; + +new Vue({ + el: '.js-todo-app', + components: { + todoComponent, + }, + render: createElement => createElement('todo-component' { + props: { + someProp: [], + } + }), +}); -The Service is used only to communicate with the server. -It does not store or manipulate any data. -We use [vue-resource][vue-resource-repo] to -communicate with the server. +``` -The [issue boards service][issue-boards-service] -is a good example of this pattern. +The [issue boards service][issue-boards-service] is a good example of this pattern. ## Style guide Please refer to the Vue section of our [style guide](style_guide_js.md#vuejs) for best practices while writing your Vue components and templates. +## Testing Vue Components + +Each Vue component has a unique output. This output is always present in the render function. + +Although we can test each method of a Vue component individually, our goal must be to test the output +of the render/template function, which represents the state at all times. + +Make use of Vue Resource Interceptors to mock data returned by the service. + +Here's how we would test the Todo App above: + +```javascript +import component from 'todos_main_component'; + +describe('Todos App', () => { + it('should render the loading state while the request is being made', () => { + const Component = Vue.extend(component); + + const vm = new Component().$mount(); + + expect(vm.$el.querySelector('i.fa-spin')).toBeDefined(); + }); + + describe('with data', () => { + // Mock the service to return data + const interceptor = (request, next) => { + next(request.respondWith(JSON.stringify([{ + title: 'This is a todo', + body: 'This is the text' + }]), { + status: 200, + })); + }; + + let vm; + + beforeEach(() => { + Vue.http.interceptors.push(interceptor); + + const Component = Vue.extend(component); + + vm = new Component().$mount(); + }); + + afterEach(() => { + Vue.http.interceptors = _.without(Vue.http.interceptors, interceptor); + }); + + + it('should render todos', (done) => { + setTimeout(() => { + expect(vm.$el.querySelectorAll('.js-todo-list div').length).toBe(1); + done(); + }, 0); + }); + }); + + describe('add todo', () => { + let vm; + beforeEach(() => { + const Component = Vue.extend(component); + vm = new Component().$mount(); + }); + it('should add a todos', (done) => { + setTimeout(() => { + vm.$el.querySelector('.js-add-todo').click(); + + // Add a new interceptor to mock the add Todo request + Vue.nextTick(() => { + expect(vm.$el.querySelectorAll('.js-todo-list div').length).toBe(2); + }); + }, 0); + }); + }); +}); +``` + +### Stubbing API responses +[Vue Resource Interceptors][vue-resource-interceptor] allow us to add a interceptor with +the response we need: + +```javascript + // Mock the service to return data + const interceptor = (request, next) => { + next(request.respondWith(JSON.stringify([{ + title: 'This is a todo', + body: 'This is the text' + }]), { + status: 200, + })); + }; + + beforeEach(() => { + Vue.http.interceptors.push(interceptor); + }); + + afterEach(() => { + Vue.http.interceptors = _.without(Vue.http.interceptors, interceptor); + }); + + it('should do something', (done) => { + setTimeout(() => { + // Test received data + done(); + }, 0); + }); +``` + [vue-docs]: http://vuejs.org/guide/index.html [issue-boards]: https://gitlab.com/gitlab-org/gitlab-ce/tree/master/app/assets/javascripts/boards @@ -100,5 +410,8 @@ for best practices while writing your Vue components and templates. [page_specific_javascript]: https://docs.gitlab.com/ce/development/frontend.html#page-specific-javascript [component-system]: https://vuejs.org/v2/guide/#Composing-with-Components [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 [vue-resource-repo]: https://github.com/pagekit/vue-resource +[vue-resource-interceptor]: https://github.com/pagekit/vue-resource/blob/develop/docs/http.md#interceptors [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 -- GitLab