Skip to content

πŸ”‘ Vue.js scalable boilerplate with user authentication.

Notifications You must be signed in to change notification settings

lbwa/vue-auth-boilerplate

Repository files navigation

Vue auth boilerplate

github actions - tests github actions - deployment nodejs version

Vue.js console boilerplate with authentication.

Prerequisites

Please make sure you have installed node.js version 8.9 or above (the LTS version recommended).

Development

  • install all dependencies

    $ npm i
  • start development server

    $ npm run serve

    Frontend server is running at http://localhost:8080 and http://<YOUR_DEVICE_LOCAL_IP>:8080 with hot module replacement.

  • run unit tests

    $ npm run test:unit

Production build

$ npm run build
# yarn build

CDN supporting

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'
    +  }
    ]

User authentication

Please refer to v-access documentation.

Symbolic constants

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.

Environment variables

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.

Declarations

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.

Layouts

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

Use route-based layout

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.

Use non-route-based layout

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
  }
}

Components

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

Plugins

If any Vue.js plugin exists, it should be placed in src/plugins directory.

Effects

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.

Router

filename description
guards.ts store all navigation guards
index.ts export a vue-router instance
routes.ts record all valid preset static routes

Route config

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.

State management

We use Vuex to implement global state management.

Automatic registration

All store module placed in src/store/modules/*.ts would be registered automatically. Every module would use their filename as store module namespace.

With request effects

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

Handle error

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

History store module

We have a history (store/modules/history.ts) store module that used to record any visited vue-route record with meta.title field.

Changelog

All notable changes to this repository will be documented in CHANGELOG file.

License

MIT Β© Bowen Liu