Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend plugin functionalities #571

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
41 changes: 35 additions & 6 deletions src/index.js
Expand Up @@ -49,8 +49,33 @@ class Store {
// (also registers _wrappedGetters as computed properties)
resetStoreVM(this, state)

// helper to make the first of 3 arguments optional
function shiftArguments (fn) {
return function (...args) {
while (args.length < 3) {
args.unshift(null)
}
fn.apply(null, args)
}
}

// allow plugins to register new properties in the context
const me = this
const registerInContext = shiftArguments(function (name, key, val) {
const context = name ? me._modules.get(name.split('.')).context : me.context
context[key] = val
})
// allow plugins to register new actions
const pluginRegisterAction = shiftArguments(function (name, type, handler) {
const context = name ? me._modules.get(name.split('.')).context : me.context
registerAction(store, type, handler, context)
})

// apply plugins
plugins.concat(devtoolPlugin).forEach(plugin => plugin(this))
plugins.concat(devtoolPlugin).forEach(plugin => plugin(this, {
registerInContext,
registerAction: pluginRegisterAction
}))
}

get state () {
Expand Down Expand Up @@ -236,7 +261,7 @@ function installModule (store, rootState, path, module, hot) {
})
}

const local = module.context = makeLocalContext(store, namespace, path)
const local = (isRoot ? store : module).context = makeLocalContext(store, namespace, path)

module.forEachMutation((mutation, key) => {
const namespacedType = namespace + key
Expand Down Expand Up @@ -348,14 +373,18 @@ function registerMutation (store, type, handler, local) {
function registerAction (store, type, handler, local) {
const entry = store._actions[type] || (store._actions[type] = [])
entry.push(function wrappedActionHandler (payload, cb) {
let res = handler({
dispatch: local.dispatch,
commit: local.commit,
const context = {
getters: local.getters,
state: local.state,
rootGetters: store.getters,
rootState: store.state
}, payload, cb)
}
// bring in commit, dispatch and any other added property
// Use this because IE doesn't supprot Object.assign
for (const key in local) {
context[key] = local[key]
}
let res = handler(context, payload, cb)
if (!isPromise(res)) {
res = Promise.resolve(res)
}
Expand Down
29 changes: 0 additions & 29 deletions test/unit/modules.spec.js
Expand Up @@ -465,34 +465,5 @@ describe('Modules', () => {
done()
})
})

it('plugins', function () {
let initState
const mutations = []
const store = new Vuex.Store({
state: {
a: 1
},
mutations: {
[TEST] (state, n) {
state.a += n
}
},
plugins: [
store => {
initState = store.state
store.subscribe((mut, state) => {
expect(state).toBe(store.state)
mutations.push(mut)
})
}
]
})
expect(initState).toBe(store.state)
store.commit(TEST, 2)
expect(mutations.length).toBe(1)
expect(mutations[0].type).toBe(TEST)
expect(mutations[0].payload).toBe(2)
})
})
})
114 changes: 114 additions & 0 deletions test/unit/plugins.spec.js
@@ -0,0 +1,114 @@
import Vue from 'vue/dist/vue.common.js'
import Vuex from '../../dist/vuex.js'

const TEST = 'TEST'

describe('Plugins', () => {
it('executes plugins function', function () {
let initState
const mutations = []
const store = new Vuex.Store({
state: {
a: 1
},
mutations: {
[TEST] (state, n) {
state.a += n
}
},
plugins: [
store => {
initState = store.state
store.subscribe((mut, state) => {
expect(state).toBe(store.state)
mutations.push(mut)
})
}
]
})
expect(initState).toBe(store.state)
store.commit(TEST, 2)
expect(mutations.length).toBe(1)
expect(mutations[0].type).toBe(TEST)
expect(mutations[0].payload).toBe(2)
})

it('injects into store context', async function (done) {
const store = new Vuex.Store({
state: { a: 1 },
actions: {
useFoo: ({ foo }) => foo
},
modules: {
module: {
actions: {
moduleAction: ({ foo }) => foo
}
}
},
plugins: [
(store, { registerInContext }) => {
registerInContext('foo', 'foo')
}
]
})
expect(await store.dispatch('useFoo')).toBe('foo')
expect(await store.dispatch('moduleAction')).toBe(undefined)
done()
})

it('injects into modules context', async function (done) {
const store = new Vuex.Store({
state: { a: 1 },
actions: {
useFoo: ({ foo }) => foo
},
modules: {
module: {
actions: {
moduleAction: ({ foo }) => foo
}
}
},
plugins: [
(store, { registerInContext }) => {
registerInContext('module', 'foo', 'foo')
}
]
})
expect(await store.dispatch('moduleAction')).toBe('foo')
expect(await store.dispatch('useFoo')).toBe(undefined)
done()
})

it('injects actions bounded to root', async function (done) {
const store = new Vuex.Store({
state: { a: 1 },
plugins: [
(store, { registerAction }) => {
registerAction('stateA', ({ state }) => state.a)
}
]
})
expect(await store.dispatch('stateA')).toBe(1)
done()
})

it('injects actions bounded to a module', async function (done) {
const store = new Vuex.Store({
state: { a: 1 },
modules: {
module: {
state: { a: 2 }
}
},
plugins: [
(store, { registerAction }) => {
registerAction('module', 'stateA', ({ state }) => state.a)
}
]
})
expect(await store.dispatch('stateA')).toBe(2)
done()
})
})