Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/championswimmer/vuex-module-decorators
TypeScript/ES7 Decorators to create Vuex modules declaratively
https://github.com/championswimmer/vuex-module-decorators
javascript typescript vue vuejs vuex vuex-modules
Last synced: 27 days ago
JSON representation
TypeScript/ES7 Decorators to create Vuex modules declaratively
- Host: GitHub
- URL: https://github.com/championswimmer/vuex-module-decorators
- Owner: championswimmer
- License: mit
- Created: 2018-04-30T21:33:14.000Z (over 6 years ago)
- Default Branch: master
- Last Pushed: 2023-09-01T21:32:24.000Z (about 1 year ago)
- Last Synced: 2024-10-10T16:34:05.819Z (about 1 month ago)
- Topics: javascript, typescript, vue, vuejs, vuex, vuex-modules
- Language: TypeScript
- Homepage: https://championswimmer.in/vuex-module-decorators/
- Size: 2.41 MB
- Stars: 1,796
- Watchers: 22
- Forks: 170
- Open Issues: 143
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
README
# vuex-module-decorators
[![Usage Guide](https://img.shields.io/badge/usage-guide-1e90ff.svg?style=for-the-badge&longCache=true)](https://championswimmer.in/vuex-module-decorators/)
Detailed Guide: https://championswimmer.in/vuex-module-decorators/Typescript/ES7 Decorators to make Vuex modules a breeze
[![Build Status](https://travis-ci.org/championswimmer/vuex-module-decorators.svg?branch=master)](https://travis-ci.org/championswimmer/vuex-module-decorators)
[![npm:size:gzip](https://img.shields.io/bundlephobia/minzip/vuex-module-decorators.svg?label=npm:size:gzip)](https://bundlephobia.com/result?p=vuex-module-decorators)
[![cdn:min:gzip](https://img.badgesize.io/https://cdn.jsdelivr.net/npm/vuex-module-decorators.svg?label=cdn:min:gzip&compression=gzip)](https://cdn.jsdelivr.net/npm/vuex-module-decorators/dist/cjs/index.min.js)
[![codecov](https://codecov.io/gh/championswimmer/vuex-module-decorators/branch/master/graph/badge.svg)](https://codecov.io/gh/championswimmer/vuex-module-decorators)
[![npm](https://img.shields.io/npm/v/vuex-module-decorators.svg)](https://www.npmjs.com/package/vuex-module-decorators)
[![npm](https://img.shields.io/npm/dw/vuex-module-decorators.svg?colorB=ff0033)](https://www.npmjs.com/package/vuex-module-decorators)
![npm type definitions](https://img.shields.io/npm/types/vuex-module-decorators.svg)
[![Maintainability](https://api.codeclimate.com/v1/badges/5b1dfa8d3d4bdf409b60/maintainability)](https://codeclimate.com/github/championswimmer/vuex-module-decorators/maintainability)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/b7944c579d5c4c1d949f71a91a538d77)](https://www.codacy.com/app/championswimmer/vuex-module-decorators?utm_source=github.com&utm_medium=referral&utm_content=championswimmer/vuex-module-decorators&utm_campaign=Badge_Grade)
[![codebeat badge](https://codebeat.co/badges/0272746c-8a7d-428b-a20d-387d22bfbcfb)](https://codebeat.co/projects/github-com-championswimmer-vuex-module-decorators-master)
[![Total alerts](https://img.shields.io/lgtm/alerts/g/championswimmer/vuex-module-decorators.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/championswimmer/vuex-module-decorators/alerts/)
[![Language grade: JavaScript](https://img.shields.io/lgtm/grade/javascript/g/championswimmer/vuex-module-decorators.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/championswimmer/vuex-module-decorators/context: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 😇 ❤️- [Thomas Woo](https://www.patreon.com/user/creators?u=37365136)
## 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](CHANGELOG.md)
## 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
```shell
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.```js
// 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 ?
```js
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`
```typescript
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 ?
```typescript
import { Module, VuexModule, MutationAction } from 'vuex-module-decorators'
import { ConferencesEntity, EventsEntity } from '@/models/definitions'@Module
export default class HGAPIModule extends VuexModule {
conferences: Array = []
events: Array = []// '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
```typescript
@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
```javascript
const module = {
state: { wheels: 2 },
mutations: {
incrWheels(state, extra) {
state.wheels += extra
}
},
getters: {
axles: (state) => state.wheels / 2
}
}
```## Parameters inside a getter
In order to handle parameters, simply return a function like so:
```
get getUser() {
return function (id: number) {
return this.users.filter(user => user.id === id)[0];
}
}
```### Putting into the store
Use the modules just like you would earlier
```typescript
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](https://vuex.vuejs.org/guide/modules.html#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:```typescript
@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
```javascript
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```typescript
interface StoreType {
mm: MyModule
}
// Declare empty store first
const store = new Vuex.Store({})// 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](https://www.npmjs.com/package/vuex-persist)
```diff
...-- @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
```diff
...-- @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`:
```typescript
import { Store } from 'vuex'
import { initialiseStores } from '~/utils/store-accessor'
const initializer = (store: Store) => initialiseStores(store)
export const plugins = [initializer]
export * from '~/utils/store-accessor'
````~/utils/store-accessor.ts`:
```typescript
import { Store } from 'vuex'
import { getModule } from 'vuex-module-decorators'
import example from '~/store/example'let exampleStore: example
function initialiseStores(store: Store): 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.
```typescript
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
```typescript
// 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:```typescript
import { config } from 'vuex-module-decorators'
// Set rawError to true by default on all @Action decorators
config.rawError = true
```