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

v1.1.1

Published

Decouple vuex modules from each other.

Downloads

2

Readme

vuex-inject

Decouple Vuex modules from each other.

Build Status Coverage Status NPM version

Installation

$ npm install vuex-inject

Usage

import modules from 'src/store/modules';
import createInjectPlugin from 'vuex-inject';

const store = new Vuex.Store({
  // pass 'modules' to the plugin instead of store
  plugins: [
    createInjectPlugin({
     modules,
     inject: {
       modA: {
         getters: { modBList: 'modB/list' },
       },
     },
    }),
  ],
  // modules,
});

Example

Let's have a look at the following simple vuex modules:

// store/modules/app.js
export default {
  namespaced: true,
  getters: {
    version: () => '0.1',
  },
};

// store/modules/rest.js
export default {
  namespaced: true,
  getters: {
    baseRestUrl: (state, getters, rootState, rootGetters) => {
      let appVersion = rootGetters['app/version'];
      return `/api/${appVersion}`;
    },
  },
};

// store/index.js
// ...
export default function initStore (params) {
  return Vuex.store({
    modules: { app, rest },
    ...params,
  });
};

rest module is coupled with app module: we can't use it or test it separately.

Let's rewrite rest module with the plugin:

// store/modules/rest.js
export default {
  namespaced: true,
  getters: {
    baseRestUrl: (state, getters) => {
      return `/api/${getters.$appVersion}`;
    },
    // $ here doesn't have any special meaning
    $appVersion: () => '',
  },
};

// store/index.js
// ...
export default function initStore (params, injectParams) {
  return new Vuex.Store({
    plugins: [
      createInjectPlugin({
        modules: { app, rest },
        inject: {
          rest: {
            getters: { $appVersion: 'app/version' },
          },
        },
        ...injectParams,
      }),
    ],
    ...params,
  });
};

Now rest module knows nothing about app module and it can be tested separately but in a more "integrated" way (through the store) than unit tests for each function in a module config:

import initStore from './store';

describe('rest', () => {
  it('should have baseRestUrl', () => {
    let store = initStore({}, {
      inject: {
        rest: {
          getters: { $appVersion: () => '1.1' },
        },
      },
    });
    expect(store.getters['rest/baseRestUrl']).toBe('/api/1.1');
  });
});

What's inside

The injections are quite simple. When the following module will be passed to createInjectPlugin:

export default {
  namespaced: true,

  getters: {
    $todoList: () => [],
    $todoTitle: () => '',
  },

  actions: {
    $addTodoItem: () => {},
    $mutateTodoTitle: () => {},
  },

  inject: {
    getters: {
      $todoList: 'todo/list',
    },
    state: {
      // Note: state will be injected as getter
      $todoTitle: 'todo/form.title',
    },
    actions: {
      $addTodoItem: 'todo/addItem',
    },
    mutations: {
      // Note: mutation will be injected as action
      $mutateTodoTitle: 'todo/setTitle',
    },
  },
};

the module functions will be replaced with something like this:

export default {
  namespaced: true,

  getters: {
    $todoList: (s, g, rootGetters) => rootGetters['todo/list'],
    $todoTitle: (s, g, rg, rootState) => rootState.todo.form.title,
  },

  actions: {
    $addTodoItem: ({ dispatch }, p) => {
      dispatch('todo/addItem', p, { root: true });
    },
    $mutateTodoTitle: ({ commit }, value) => {
      commit('todo/setTitle', value, { root: true });
    },
  },
};

Conditional injection

Conditional injections may help implement dynamic feature toggles. If the module, we are injecting from, has isInjectable (default name) getter and its value is false, then all the parts injected from that module will return default (original) values, until isInjectable getter become true.

Example:

// store/modules/profile.js
export default {
  namespaced: true,

  state: {
    isFeatureEnabled: false,
    groups: ['user', 'admin'],
  },

  getters: {
    isInjectable: state => state.isFeatureEnabled,
  },

  mutations: {
    setFeatureStatus: (state, value) => { state.isFeatureEnabled = value; },
  },
};


// store/modules/acl.js
export default {
  namespaced: true,

  getters: {
    isAdmin: (state, getters) => getters.$profileGroups.indexOf('admin') >= 0,
    $profileGroups: () => [],
  },

  inject: {
    state: {
      $profileGroups: 'profile/groups',
    },
  },
};


// test
describe('acl', () => {
  it('should have conditional injection', () => {
    let store = initStore();

    // profile feature is turned off,
    // default implementation for $profileGroups
    expect(store.getters['acl/$profileGroups']).toEqual([]);
    expect(store.getters['acl/isAdmin']).toBe(false);

    // profile feature should be toggled for beta user
    store.commit('profile/setFeatureStatus', true);

    // profile/groups become available
    expect(store.getters['acl/$profileGroups']).toEqual(['user', 'admin']);
    expect(store.getters['acl/isAdmin']).toBe(true);
  });
});

API

createInjectPlugin(options)

Creates a new instance of the plugin with the given options. The following options can be provided:

  • modules <Object>: store modules config. We pass it here instead of store constructor.
  • inject <Object>: injection config. This config has precedence over inner module inject config.
  • moduleField <String>: Inner module inject config will be looked under this name. Defaults to inject
  • conditionalGetterName <String>: Getter name to check to find out if conditional injection is allowed. Defaults to isInjectable

License

MIT © Denis Pobelov