Vue.js
console boilerplate with authentication.
- Prerequisites
- Development
- Production build
- User authentication
- Symbolic constants
- Environment variables
- Declarations
- Layouts
- Components
- Plugins
- Effects
- Router
- State management
- Changelog
- License
Please make sure you have installed node.js version 8.9 or above (the LTS version recommended).
-
install all dependencies
$ npm i
-
start development server
$ npm run serve
Frontend server is running at
http://localhost:8080
andhttp://<YOUR_DEVICE_LOCAL_IP>:8080
with hot module replacement. -
run unit tests
$ npm run test:unit
$ npm run build
# yarn build
This project production build has supported third-party CDN libraries out of the box. All JS/CSS library CDN urls should be recorded by third-parties.js. syntax like:
interface CDNUrl {
name: string // required for js, npm package name
library: string // required for js, global variable name in the browser
js: string // js cdn file urls
css: string // css cdn file urls
}
-
JS libraries
const thirdParties = [ // ... other js/css libraries + { + name: 'vue', + library: 'Vue', + js: 'https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js' + } ]
-
Pure CSS libraries
step 1. You should import pure css libraries with tree-shaking.
- import 'normalize.css' + if (__DEV__) { // __DEV__ is an environment variable + require('normalize.css') + }
step 2. add css library CDN link into third-parties.js.
const thirdParties = [ // ... other js/css libraries + { + css: 'https://cdn.jsdelivr.net/npm/[email protected]/normalize.min.css' + } ]
Please refer to v-access
documentation.
A symbolic constant is a name given to a constant literal value. It's usually used to prevent magic numbers and hard-coding. All symbolic constants should be recorded in the src/constants.ts file.
-
Q: When should I use symbolic constants?
-
A: Feature flag, public settings, etc.
All node.js
use-defined environment should be record at the <PROJECT_ROOT>/.env*
files and start with VUE_APP_*
prefix character. You can find more details from the @vue/cli documentation.
All global TypeScript
declarations should be recorded in the src/global.d.ts file.
This boilerplate has supported multiple declarations for CSS pre-process languages in src/global.d.ts.
In practice, we perhaps have two different kinds of layout components. All layout components should be placed in the src/layouts directory.
type | description | character |
---|---|---|
route-based layout |
with <router-view/> |
src/layouts/R*.vue |
non-route-based layout |
without <router-view/> |
src/layouts/L*.vue |
A valid router config should be based on the following structure:
interface ConsoleRouteConfig extends RouteConfig {
meta?: Partial<{
layout: string // which route-based layout need to be rendered
hidden: boolean
icon: string
title: string
}>
}
We use meta.layout
to decide which layout component we need to be rendered.
As opposed to route-based
layout, you should always import non-route-based
layout component manually.
import { NonRouteBasedLayout } from '@/layouts/NonRouteBasedLayout'
export default {
name: 'AnyViewComponent',
components: {
NonRouteBasedLayout
}
}
We also have multiple kinds of components and should be placed in src/components directory.
component type | description | example | character |
---|---|---|---|
presentational | represent user interface view excluding any state | basic component | Base*.vue |
container | state including all business logic | any sub views/layouts component |
[VIEW_PREFIX]*.vue |
If any Vue.js
plugin exists, it should be placed in src/plugins directory.
All HTTP request function should be placed in src/effects directory, and should be occurred by Initiator instance which has encapsulated axios
creation and registered two interceptors automatically by default.
import { createInitiator } from './initiator'
const { http } = createInitiator(/* support all AxiosRequestConfig */)
export function fetchUserProfile(username: string, password: string) {
return http.post('/user/profile', {
username,
password
})
}
Based on single responsibility principle and better universality, every request route should be a singleton. All request or response errors should be handle by Http request consumer, instead of itself.
filename | description |
---|---|
guards.ts |
store all navigation guards |
index.ts |
export a vue-router instance |
routes.ts |
record all valid preset static routes |
We add serval meta
properties for global navigation sidebar.
interface ConsoleRouteConfig extends RouteConfig {
meta?: Partial<{
layout: string // which route-based layout need to be rendered
hidden: boolean
icon: string
title: string
}>
}
property name | description |
---|---|
meta.layout |
Which route-based layout should be rendered |
meta.hidden |
Whether route should be rendered by global navigation sidebar |
meta.icon |
Route material design icon icon in the global navigation sidebar |
meta.title |
Route title in the global navigation sidebar |
Note that Route only be rendered when meta.title
and meta.hidden
is truthy value.
We use Vuex
to implement global state management.
All store module placed in src/store/modules/*.ts would be registered automatically. Every module would use their filename as store module namespace.
Actions can contain arbitrary asynchronous operations.
All HTTP requests should be called by an action if an HTTP request result needs to be stored in the vuex store, instead of calling HTTP request directly.
dispatch an action --> http effects --> commit mutation in an action --> store the result of effects
store.dispatch always return a
Promise
instance.
Any action internal error should be handled by action consumer, instead of action itself.
action's error --> throw --as rejected promise--> handled by any action consumer
We have a history
(store/modules/history.ts) store module that used to record any visited vue-route record
with meta.title
field.
All notable changes to this repository will be documented in CHANGELOG file.
MIT Β© Bowen Liu