├── .browserslistrc ├── .editorconfig ├── .eslintrc.js ├── .gitignore ├── README.md ├── babel.config.js ├── package-lock.json ├── package.json ├── public ├── favicon.ico └── index.html └── src ├── App.vue ├── assets ├── .gitkeep ├── banner.jpg └── screen.png ├── components └── Banner.vue ├── main.js ├── router ├── index.js └── routes.js ├── services ├── index.js └── users.js ├── store ├── index.js ├── modules │ ├── Users.js │ └── index.js └── root.js ├── utils ├── enum.js ├── localStorage.js └── request.js └── views └── Home.vue /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not ie <= 8 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{js,jsx,ts,tsx,vue}] 2 | indent_style = space 3 | indent_size = 2 4 | end_of_line = lf 5 | trim_trailing_whitespace = true 6 | insert_final_newline = true 7 | max_line_length = 100 8 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | browser: true, 5 | }, 6 | extends: [ 7 | 'plugin:vue/recommended', 8 | '@vue/airbnb', 9 | ], 10 | plugins: [ 11 | 'vue', 12 | ], 13 | rules: { 14 | 'prefer-destructuring': 'off', 15 | camelcase: 'error', 16 | 'no-new': 'error', 17 | 'no-unused-vars': 'error', 18 | 'max-len': ['error', { code: 100 }], 19 | 'import/no-dynamic-require': 'allow', 20 | 'no-console': 'error', 21 | 'padded-blocks': ['error', 'never'], 22 | 'no-unused-expressions': 'error', 23 | // allow optionalDependencies 24 | 'import/no-extraneous-dependencies': ['error', { 25 | optionalDependencies: ['test/unit/index.js'], 26 | }], 27 | // disallow reassignment of function parameters 28 | // disallow parameter object manipulation except for specific exclusions 29 | 'no-param-reassign': ['error', { 30 | props: true, 31 | ignorePropertyModificationsFor: [ 32 | 'state', // for vuex state 33 | 'acc', // for reduce accumulators 34 | 'e', // for e.returnvalue 35 | 'Vue', // for Vue.prototype 36 | 'config', 37 | ], 38 | }], 39 | 'no-plusplus': 'off', 40 | 'comma-dangle': ['error', 'always-multiline'], 41 | semi: ['error', 'always'], 42 | 'no-confusing-arrow': 'off', 43 | 'arrow-parens': 'off', 44 | 'consistent-return': 'off', 45 | 'no-alert': 'off', 46 | 'no-underscore-dangle': 'off', 47 | 'import/prefer-default-export': 'off', 48 | 'import/extensions': ['error', 'always', { 49 | js: 'never', 50 | vue: 'never', 51 | }], 52 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', 53 | }, 54 | parserOptions: { 55 | parser: 'babel-eslint', 56 | }, 57 | }; 58 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw* 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 |

3 | Vue Architecture Boilerplate 4 |

5 |

6 | Vue.js architecture for front-end projects. 7 |

8 |

9 | 10 | ![screenshot](/src/assets/screen.png) 11 | 12 | ### Project setup 13 | 14 | ```sh 15 | # Install Deps 16 | npm install 17 | 18 | # Compiles and hot-reloads for development 19 | npm run serve 20 | 21 | # Compiles and minifies for production 22 | npm run build 23 | ``` 24 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/app', 4 | ], 5 | }; 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-architecture-boilerplate", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "axios": "^0.18.1", 12 | "vue": "^2.6.6", 13 | "vue-router": "^3.0.1", 14 | "vuex": "^3.0.1" 15 | }, 16 | "devDependencies": { 17 | "@vue/cli-plugin-babel": "^3.4.0", 18 | "@vue/cli-plugin-eslint": "^3.4.0", 19 | "@vue/cli-service": "^3.4.0", 20 | "@vue/eslint-config-airbnb": "^4.0.0", 21 | "babel-eslint": "^10.0.1", 22 | "eslint": "^5.8.0", 23 | "eslint-plugin-vue": "^5.0.0", 24 | "fibers": "^3.1.1", 25 | "lint-staged": "^8.1.0", 26 | "sass": "^1.16.0", 27 | "sass-loader": "^7.1.0", 28 | "vue-template-compiler": "^2.5.21" 29 | }, 30 | "gitHooks": { 31 | "pre-commit": "lint-staged" 32 | }, 33 | "lint-staged": { 34 | "*.js": [ 35 | "vue-cli-service lint", 36 | "git add" 37 | ], 38 | "*.vue": [ 39 | "vue-cli-service lint", 40 | "git add" 41 | ] 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IgorHalfeld/vue-architecture-boilerplate/c49f9d40295a27c56f7781540187e7b64a93d8e7/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Vue Architecture Boilerplate 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 25 | -------------------------------------------------------------------------------- /src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IgorHalfeld/vue-architecture-boilerplate/c49f9d40295a27c56f7781540187e7b64a93d8e7/src/assets/.gitkeep -------------------------------------------------------------------------------- /src/assets/banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IgorHalfeld/vue-architecture-boilerplate/c49f9d40295a27c56f7781540187e7b64a93d8e7/src/assets/banner.jpg -------------------------------------------------------------------------------- /src/assets/screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IgorHalfeld/vue-architecture-boilerplate/c49f9d40295a27c56f7781540187e7b64a93d8e7/src/assets/screen.png -------------------------------------------------------------------------------- /src/components/Banner.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 17 | 18 | 61 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | 3 | import App from './App'; 4 | import router from './router'; 5 | import store from './store'; 6 | 7 | Vue.config.productionTip = false; 8 | 9 | new Vue({ 10 | router, 11 | store, 12 | render: h => h(App), 13 | }).$mount('#app'); 14 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Router from 'vue-router'; 3 | import routes from './routes'; 4 | 5 | Vue.use(Router); 6 | 7 | export default new Router({ 8 | mode: 'history', 9 | base: process.env.BASE_URL, 10 | routes, 11 | }); 12 | -------------------------------------------------------------------------------- /src/router/routes.js: -------------------------------------------------------------------------------- 1 | import Home from '../views/Home'; 2 | 3 | export default [ 4 | { 5 | path: '/', 6 | name: 'home', 7 | component: Home, 8 | }, 9 | ]; 10 | -------------------------------------------------------------------------------- /src/services/index.js: -------------------------------------------------------------------------------- 1 | import users from './users'; 2 | 3 | export { users }; 4 | -------------------------------------------------------------------------------- /src/services/users.js: -------------------------------------------------------------------------------- 1 | import { HTTPClient } from '../utils/request'; 2 | 3 | export default { 4 | create: ({ payload }) => HTTPClient.post('/users', payload), 5 | }; 6 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Vuex from 'vuex'; 3 | 4 | import modules from './modules'; 5 | import rootStore from './root'; 6 | 7 | Vue.use(Vuex); 8 | 9 | export default new Vuex.Store({ 10 | modules, 11 | ...rootStore, 12 | }); 13 | -------------------------------------------------------------------------------- /src/store/modules/Users.js: -------------------------------------------------------------------------------- 1 | export default { 2 | namespaced: true, 3 | state: {}, 4 | actions: {}, 5 | mutations: {}, 6 | getters: {}, 7 | }; 8 | -------------------------------------------------------------------------------- /src/store/modules/index.js: -------------------------------------------------------------------------------- 1 | import Users from './Users'; 2 | 3 | export default { 4 | Users, 5 | }; 6 | -------------------------------------------------------------------------------- /src/store/root.js: -------------------------------------------------------------------------------- 1 | import { parseNetworkError } from '../utils/request'; 2 | import * as apiMethods from '../services'; 3 | 4 | export const SET_API_CALL_IN_PROGRESS = 'SET_API_CALL_IN_PROGRESS'; 5 | export const SET_GENERAL_ERRORS = 'SET_GENERAL_ERRORS'; 6 | 7 | export default { 8 | state: { 9 | isAPICallInProgress: false, 10 | generalErrors: [], 11 | }, 12 | mutations: { 13 | [SET_API_CALL_IN_PROGRESS]: (state, status) => { 14 | state.isAPICallInProgress = status; 15 | }, 16 | [SET_GENERAL_ERRORS]: (state, error) => { 17 | state.generalErrors.push(error); 18 | }, 19 | }, 20 | actions: { 21 | /** 22 | * Dispatch AJAX calls 23 | * @param {String} entity e.g. `users` 24 | * @param {String} action method name eg. `getById` 25 | */ 26 | async api({ commit }, { 27 | entity, action, payload = {}, query, params, 28 | }) { 29 | try { 30 | const response = await apiMethods[entity][action]({ payload, query, params }); 31 | return response; 32 | } catch (error) { 33 | const errorPayload = { [`${entity}_${action}_request`]: parseNetworkError(error) }; 34 | commit(SET_GENERAL_ERRORS, errorPayload); 35 | } 36 | }, 37 | }, 38 | }; 39 | -------------------------------------------------------------------------------- /src/utils/enum.js: -------------------------------------------------------------------------------- 1 | export const DEFAULT_API_URLS = { 2 | LOCAL: '', 3 | PRODUCTION: '', 4 | DEVELOPMENT: '', 5 | }; 6 | -------------------------------------------------------------------------------- /src/utils/localStorage.js: -------------------------------------------------------------------------------- 1 | const { stringify, parse } = JSON; 2 | 3 | export const setStorage = (key, value, { format } = {}) => { 4 | if (!window) return; 5 | window.localStorage.setItem(key, format ? stringify(value) : value); 6 | }; 7 | 8 | export const getStorage = (key, { format } = {}) => { 9 | if (!window) return; 10 | const value = window.localStorage.getItem(key); 11 | return format 12 | ? parse(window.localStorage.getItem(key)) 13 | : value; 14 | }; 15 | -------------------------------------------------------------------------------- /src/utils/request.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import { DEFAULT_API_URLS } from './enum'; 3 | import { getStorage } from './localStorage'; 4 | 5 | import store from '../store'; 6 | import { SET_API_CALL_IN_PROGRESS } from '../store/root'; 7 | 8 | const { stringify, parse } = JSON; 9 | export const parseNetworkError = error => parse(stringify(error)); 10 | 11 | const withBaseURLContext = () => process.env.NODE_ENV 12 | ? DEFAULT_API_URLS[process.env.NODE_ENV.toUpperCase()] 13 | : DEFAULT_API_URLS.development; 14 | 15 | const HTTPClient = axios.create({ 16 | baseURL: withBaseURLContext(), 17 | }); 18 | 19 | HTTPClient.interceptors.request.use(config => { 20 | store.commit(SET_API_CALL_IN_PROGRESS, true); 21 | 22 | const token = getStorage('token'); 23 | if (token) { 24 | config.headers.common.Authorization = `Bearer ${token}`; 25 | } 26 | 27 | return config; 28 | }, response => Promise.reject(response)); 29 | 30 | HTTPClient.interceptors.response.use(response => { 31 | store.commit(SET_API_CALL_IN_PROGRESS, false); 32 | return response; 33 | }, error => Promise.reject(error)); 34 | 35 | export { HTTPClient }; 36 | -------------------------------------------------------------------------------- /src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 15 | 16 | 22 | --------------------------------------------------------------------------------