Nutritious Polygonal Meatball

    vuex-module-decorators
    TypeScript icon, indicating that this package has built-in type declarations

    2.0.0 • Public • Published

    vuex-module-decorators

    Usage Guide Detailed Guide: https://championswimmer.in/vuex-module-decorators/

    Typescript/ES7 Decorators to make Vuex modules a breeze

    Build Status npm:size:gzip cdn:min:gzip codecov npm npm npm type definitions Maintainability Codacy Badge codebeat badge Total alerts Language grade: JavaScript

    Patrons

    While I have a day job and I really maintain open source libraries for fun, any sponsors are extremely graciously thanked for their contributions, and goes a long way 😇 ❤️

    CHANGELOG

    • There are major type-checking changes (could be breaking) in v0.9.7

    • There are major usage improvements (non backwards compatible) in 0.8.0

    Please check CHANGELOG

    Examples

    Read the rest of the README to figure out how to use, or if you readily want to jump into a production codebase and see how this is used, you can check out -

    Installation

    npm install -D vuex-module-decorators

    Babel 6/7

    NOTE This is not necessary for vue-cli@3 projects, since @vue/babel-preset-app already includes this plugin

    1. You need to install babel-plugin-transform-decorators

    TypeScript

    1. set experimentalDecorators to true
    2. For reduced code with decorators, set importHelpers: true in tsconfig.json
    3. (only for TypeScript 2) set emitHelpers: true in tsconfig.json

    Configuration

    Using with target: es5

    NOTE Since version 0.9.3 we distribute as ES5, so this section is applicable only to v0.9.2 and below

    This package generates code in es2015 format. If your Vue project targets ES6 or ES2015 then you need not do anything. But in case your project uses es5 target (to support old browsers), then you need to tell Vue CLI / Babel to transpile this package.

    // in your vue.config.js
    module.exports = {
      /* ... other settings */
      transpileDependencies: ['vuex-module-decorators']
    }

    Usage

    The conventional old & boring way

    Remember how vuex modules used to be made ?

    const moduleA = {
      state: { ... },
      mutations: { ... },
      actions: { ... },
      getters: { ... }
    }
    
    const moduleB = {
      state: { ... },
      mutations: { ... },
      actions: { ... }
    }
    
    const store = new Vuex.Store({
      modules: {
        a: moduleA,
        b: moduleB
      }
    })

    Hello Decorators !

    Well not anymore. Now you get better syntax. Inspired by vue-class-component

    import { Module, VuexModule, Mutation, Action } from 'vuex-module-decorators'
    
    @Module
    export default class Counter2 extends VuexModule {
      count = 0
    
      @Mutation
      increment(delta: number) {
        this.count += delta
      }
      @Mutation
      decrement(delta: number) {
        this.count -= delta
      }
    
      // action 'incr' commits mutation 'increment' when done with return value as payload
      @Action({ commit: 'increment' })
      incr() {
        return 5
      }
      // action 'decr' commits mutation 'decrement' when done with return value as payload
      @Action({ commit: 'decrement' })
      decr() {
        return 5
      }
    }

    async MutationAction === magic

    Want to see something even better ?

    import { Module, VuexModule, MutationAction } from 'vuex-module-decorators'
    import { ConferencesEntity, EventsEntity } from '@/models/definitions'
    
    @Module
    export default class HGAPIModule extends VuexModule {
      conferences: Array<ConferencesEntity> = []
      events: Array<EventsEntity> = []
    
      // 'events' and 'conferences' are replaced by returned object
      // whose shape must be `{events: [...], conferences: [...] }`
      @MutationAction({ mutate: ['events', 'conferences'] })
      async fetchAll() {
        const response: Response = await getJSON('https://hasgeek.github.io/events/api/events.json')
        return response
      }
    }

    Automatic getter detection

    @Module
    class MyModule extends VuexModule {
      wheels = 2
    
      @Mutation
      incrWheels(extra) {
        this.wheels += extra
      }
    
      get axles() {
        return this.wheels / 2
      }
    }

    this is turned into the equivalent

    const module = {
      state: { wheels: 2 },
      mutations: {
        incrWheels(state, extra) {
          state.wheels += extra
        }
      },
      getters: {
        axles: (state) => state.wheels / 2
      }
    }

    Putting into the store

    Use the modules just like you would earlier

    import Vue from 'nativescript-vue'
    import Vuex, { Module } from 'vuex'
    
    import counter from './modules/Counter2'
    import hgapi from './modules/HGAPIModule'
    
    Vue.use(Vuex)
    
    const store = new Vuex.Store({
      state: {},
      modules: {
        counter,
        hgapi
      }
    })

    Module re-use, use with NuxtJS

    If you need to support module reuse or to use modules with NuxtJS, you can have a state factory function generated instead of a static state object instance by using stateFactory option to @Module, like so:

    @Module({ stateFactory: true })
    class MyModule extends VuexModule {
      wheels = 2
    
      @Mutation
      incrWheels(extra) {
        this.wheels += extra
      }
    
      get axles() {
        return this.wheels / 2
      }
    }

    this is turned into the equivalent

    const module = {
      state() {
        return { wheels: 2 }
      },
    
      mutations: {
        incrWheels(state, extra) {
          state.wheels += extra
        }
      },
      getters: {
        axles: (state) => state.wheels / 2
      }
    }

    Dynamic Modules

    Vuex allows us to register modules into store at runtime after store is constructed. We can do the following to create dynamic modules

    interface StoreType {
      mm: MyModule
    }
    // Declare empty store first
    const store = new Vuex.Store<StoreType>({})
    
    // Create module later in your code (it will register itself automatically)
    // In the decorator we pass the store object into which module is injected
    // NOTE: When you set dynamic true, make sure you give module a name
    @Module({ dynamic: true, store: store, name: 'mm' })
    class MyModule extends VuexModule {
      count = 0
    
      @Mutation
      incrCount(delta) {
        this.count += delta
      }
    }

    If you would like to preserve the state e.g when loading in the state from vuex-persist

    ...
    
    -- @Module({ dynamic: true, store: store, name: 'mm' })
    ++ @Module({ dynamic: true, store: store, name: 'mm', preserveState: true })
    class MyModule extends VuexModule {
    
    ...

    Or when it doesn't have a initial state and you load the state from the localStorage

    ...
    
    -- @Module({ dynamic: true, store: store, name: 'mm' })
    ++ @Module({ dynamic: true, store: store, name: 'mm', preserveState: localStorage.getItem('vuex') !== null })
    class MyModule extends VuexModule {
    
    ...

    Accessing modules with NuxtJS

    There are many possible ways to construct your modules. Here is one way for drop-in use with NuxtJS (you simply need to add your modules to ~/utils/store-accessor.ts and then just import the modules from ~/store):

    ~/store/index.ts:

    import { Store } from 'vuex'
    import { initialiseStores } from '~/utils/store-accessor'
    const initializer = (store: Store<any>) => initialiseStores(store)
    export const plugins = [initializer]
    export * from '~/utils/store-accessor'

    ~/utils/store-accessor.ts:

    import { Store } from 'vuex'
    import { getModule } from 'vuex-module-decorators'
    import example from '~/store/example'
    
    let exampleStore: example
    
    function initialiseStores(store: Store<any>): void {
      exampleStore = getModule(example, store)
    }
    
    export { initialiseStores, exampleStore }

    Now you can access stores in a type-safe way by doing the following from a component or page - no extra initialization required.

    import { exampleStore } from '~/store'
    ...
    someMethod() {
      return exampleStore.exampleGetter
    }

    Using the decorators with ServerSideRender

    When SSR is involved the store is recreated on each request. Every time the module is accessed using getModule function the current store instance must be provided and the module must be manually registered to the root store modules

    Example

    // store/modules/MyStoreModule.ts
    import { Module, VuexModule, Mutation } from 'vuex-module-decorators'
    
    @Module({
      name: 'modules/MyStoreModule',
      namespaced: true,
      stateFactory: true,
    })
    export default class MyStoreModule extends VuexModule {
      public test: string = 'initial'
    
      @Mutation
      public setTest(val: string) {
        this.test = val
      }
    }
    
    
    // store/index.ts
    import Vuex from 'vuex'
    import MyStoreModule from '~/store/modules/MyStoreModule'
    
    export function createStore() {
      return new Vuex.Store({
        modules: {
          MyStoreModule,
        }
      })
    }
    
    // components/Random.tsx
    import { Component, Vue } from 'vue-property-decorator';
    import { getModule } from 'vuex-module-decorators';
    import MyStoreModule from '~/store/modules/MyStoreModule'
    
    @Component
    export default class extends Vue {
        public created() {
            const MyModuleInstance = getModule(MyStoreModule, this.$store);
            // Do stuff with module
            MyModuleInstance.setTest('random')
        }
    }

    Configuration

    There is a global configuration object that can be used to set options across the whole module:

    import { config } from 'vuex-module-decorators'
    // Set rawError to true by default on all @Action decorators
    config.rawError = true

    Install

    npm i vuex-module-decorators

    DownloadsWeekly Downloads

    98,936

    Version

    2.0.0

    License

    MIT

    Unpacked Size

    697 kB

    Total Files

    22

    Last publish

    Collaborators

    • championswimmer