npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

vuex-module-toolkit

v0.1.19

Published

A toolkit to create typesafe modules, getters, mutations and actions

Downloads

15

Readme

vuex-module-toolkit

A toolkit to create typesafe modules, getters, mutations and actions

Mutations

TBD (but pretty much the same as actions below)

Actions

Creating

Either via factory:

const actionFactory = actionBuilderFactory<ModuleState, RootState>()

const increaseAction = actionFactory.generate<{ amount: number }, number>("increase", (
    actionContext /* ActionContext<ModuleState, RootState> */, 
    event /* { amount: number } */
) => {
    /* ... */
})

Or with a simple builder:

const increaseAction = actionBuilder<{ amount: number }, ModuleState, RootState, number>("increase", (
    actionContext /* ActionContext<ModuleState, RootState> */, 
    event /* { amount: number } */
) => {
    /* ... */
})

Factory vs Builder

If you plan to create multiple actions for one module it is advised to use a factory over a builder. Every time actionFactory.generate is called the generated action is returned and also cached in the factory itself.

By calling actionFactory.toActionTree() an action tree is returned which can be used in every vuex store/module.

Dispatch without namespace

There are multiple ways to use your actions after creation. Given the above creation (factory and builder return the functionally same):

// via typed function call into a store.dispatch
store.dispatch(increaseAction({ amount: 42 }))

// via action.dispatch with the store as first argument
increaseAction.dispatch(store, { amount: 42 })

Dispatch with namespace prefix

If you need to dispatch your actions into a specific namespace (without the type) you can also dispatch the actions directly to namespaces. All the examples below are equivalents to store.dispatch("foo/bar/increase", { amount: 42 }):

// forcing to a specific namespace via typed function call into a store.dispatch
store.dispatch(increaseAction({ amount: 42 }, { namespace: "foo/bar" }))

// by making use of the default namespaceBuilder and a custom helper `namespaced()`
// note that this call uses the namespaceBuilder provided on action creation
store.dispatch(increaseAction.namespaced("foo/bar", { amount: 42 }))

// via action.dispatchNamepsaced
// store as arguments and namespace builder arguments (see below) as arguments
// note that this call uses the namespaceBuilder provided on action creation
increaseAction.dispatchNamespaced(store, "foo/bar", { amount: 42 })

Non-reusable Modules

Readme is TBD. Use moduleBuilderFactory without namespaceBuilder (see below) and constructor args. Then create and export something like:

type ModuleState = { value: number }

const myModuleBuilder = moduleBuilderFactory<ModuleState, RootState>({
    state: () => ({ value: 0 }) // return type is the generic ModuleState
})

// calls an actionBuilderFactory internally and has the same signature as actionBuilderFactory.generate
myModule.addAction(/* ... */)

// calls a mutationBuilderFactory internally and has the same signature as mutationBuilderFactory.generate
myModule.addMutation(/* ... */)

// calling getModule() will automatically use all actions and mutations defined via addAction and addMutation
export const myModule = myModuleBuilder.getModule()

Reusable Modules

Readme is TBD. Use moduleBuilderFactory and define a namespaceBuilder (see below). Also make good use of the constructorArgs type.

type ModuleState = { value: number }
type ConstructorArgs = { initialValue: number }
type NamespaceArgs = { entityId: string }

export const myModuleBuilderFactory = moduleBuilderFactory<ModuleState, RootState, ConstructorArgs, NamespaceArgs>({
    state: (constructorArgs /* ConstructorArgs */) => ({ value: constructorArgs.initialValue }),
    namespaceBuilder: (nsArgs /* NamespaceArgs */) => "foo/" + nsArgs.entityId
})

// calls an actionBuilderFactory internally and has the same signature as actionBuilderFactory.generate
myModule.addAction(/* ... */)

// calls a mutationBuilderFactory internally and has the same signature as mutationBuilderFactory.generate
myModule.addMutation(/* ... */)

After creating and exporting a factory like so, you can dynamically register and unregister modules to your store using your moduleBuilderFactory - super type safe and with the help of the namespaceBuilder also reliably addressable with action.namespaced et al.

// register an instance of the previously defined module to the store
myModuleBuilderFactory.register(store, constructorArgs /* ConstructorArgs */, nsArgs /* NamespaceArgs */)

// unregister under a given namespace - again making use of the namespaceBuilder
// we only need NamespaceArgs because the constructorArgs are only relevant to the initial state
myModuleBuilderFactory.unregister(store, nsArgs /* NamespaceArgs */)

NamespaceBuilder

Upon creation of a factory or builder instance (i.e. actionBuilder, actionBuilderFactory, mutationBuilder, mutationBuilderFactory, ) you can provide an optional namespaceBuilder. The default is args => `${args}` .

The provided namespaceBuilder will be called with the arguments provided during

  • action.namespaced
  • action.dispatchNamespaced
  • mutation.namespaced
  • mutation.dispatchNamespaced
  • module.register

Here are some examples:

store.dispatch("foo/bar/baz", 42)

Equivalents:

With an actionBuilder:

// do note the third generic which is typing the namespaceBuilder arguments
const bazAction = actionBuilder<number, ModuleState, RootState, string>(
    "baz", 
    () => { /*...*/ }, { 
    namespaceBuilder: nsArgs => `foo/${nsArgs}`
})

// every argument is typed by actionBuilder's generics
store.dispatch(bazAction.namespaced("bar", 42))
// <=>
bazAction.dispatchNamespaced(store, "bar", 42)

With an actionBuilderFactory:

const actionFactory = actionBuilderFactory<ModuleState, RootState>({
    namespaceBuilder: nsArgs => `foo/${nsArgs}`
})

// the action receives the namespaceBuilder from the factory
// hence all actions created with this factory instance will share the same namespace builder and typings
const bazAction = actionFactory.generate<number>("baz", () => { /*...*/ })

store.dispatch(bazAction.namespaced("bar", 42))
// <=>
bazAction.dispatchNamespaced(store, "bar", 42)

Calling typed Mutations and Actions from Actions

Due to the flexibility in namespacing we can combine mutations and actions within the same module without namespace and call the actions and mutations outside the module with namespace (explained in the section above).

const increaseByMutation = mutationBuilder<number, ModuleState>("INCREASE_BY", (state, newValue) => { 
    state.value = newValue
})

const increaseByAction = actionBuilder<number, ModuleState, RootState, string>(
    "baz",
    ({ commit }, event) => { 
        const newValue = event.payload
        
        /* do something regarding your business logic, asynchronous calls, other dispatches, etc. */
        
        // call your mutation with typed arguments and no namespace
        // this is the typed equivalent to `commit("INCREASE_BY", newValue)`
        commit(increaseByMutation(newValue))
    }
)