-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Added a cookbook on how to make a useful Vue plugin #2422
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
base: master
Are you sure you want to change the base?
Changes from 5 commits
0122927
d0022f3
8c98f15
d56d983
ec97a07
810eeac
80aef2e
2ec95f1
7ee409f
37e94e4
fb5658e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,214 @@ | ||
--- | ||
title: Making use of the Vue Plugin API | ||
type: cookbook | ||
order: 15 | ||
--- | ||
|
||
## Base Example | ||
|
||
Vue exposes a really nifty API for creating plugins, plugins allow us to modify and add features to Vue. This cookbook is aimed at showing you how to take a simple idea and turn it into a full-fledged Vue plugin. | ||
|
||
Let's say we want to create a simple abstraction for using Vuex within Vue components, we want to reduce the boilerplate essentially. We can first design how we want the abstraction to look. | ||
|
||
Usually we would use Vuex like this in a Vue component: | ||
|
||
```js | ||
import { mapState, mapMutations } from 'vuex' | ||
|
||
export default { | ||
computed: { | ||
...mapState({ | ||
user: (state) => state.user, | ||
}), | ||
...mapMutations(['UPDATE_USER']), | ||
}, | ||
} | ||
``` | ||
|
||
Our abstraction would look something like this: | ||
|
||
```js | ||
export default { | ||
vuex: { | ||
state: { | ||
user: (state) => state.user, | ||
}, | ||
mutations: ['UPDATE_USER'], | ||
}, | ||
} | ||
``` | ||
|
||
## Let's build the plugin | ||
|
||
### Setting up the plugin | ||
|
||
Before we can get into the logic of the plugin, we first need to setup the plugin in a `.js` file | ||
|
||
```js | ||
import Vue from 'vue' | ||
|
||
const plugin = { | ||
install(LocalVue) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's worth a comment here or sentence above to explain what |
||
|
||
} | ||
} | ||
|
||
Vue.use(plugin) | ||
``` | ||
|
||
You might have come across `Vue.use()` before, the method is responsible for registering plugins and it takes an object with a method named `install` which gets called. | ||
|
||
The `install` hook exposes two parameters: | ||
|
||
* First parameter is the Vue constructor | ||
* Second parameter is the options that you pass to the plugin | ||
|
||
Next step is to add a global mixin in the `install` hook, we can use the `beforeCreate` lifecycle hook to add/modify the Vue component instance | ||
|
||
```js | ||
import Vue from 'vue' | ||
|
||
const plugin = { | ||
install(LocalVue) { | ||
LocalVue.mixin({ | ||
beforeCreate() { | ||
this // we can access the component instance | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nice addition, sometimes people don't know you can access |
||
} | ||
}) | ||
} | ||
} | ||
|
||
Vue.use(plugin) | ||
``` | ||
|
||
### Writing the plugin logic | ||
|
||
Now that we have all the plugin boilerplate setup, let's have a look at actually taking our abstraction and converting it to something that Vue understands. | ||
|
||
Every Vue instance has a property called `$options` which contains a reference to all the options exported in the Vue component, you can read more about the [Options API](https://vuejs.org/v2/api/?#Options-Data). | ||
|
||
#### Step 1 - Access vuex from options | ||
|
||
```js | ||
import Vue from 'vue' | ||
|
||
const plugin = { | ||
install(LocalVue) { | ||
LocalVue.mixin({ | ||
beforeCreate() { | ||
const { | ||
vuex = {}, | ||
methods = {}, | ||
computed = {}, | ||
} = this.$options | ||
} | ||
}) | ||
} | ||
} | ||
|
||
Vue.use(plugin) | ||
``` | ||
|
||
Here we are destructuring the `vuex`, `methods` and `computed` properties from the `$options` object and if it does not exist we can set a default of an empty object. | ||
|
||
#### Step 2 - Access props from vuex | ||
|
||
```js | ||
import Vue from 'vue' | ||
|
||
const plugin = { | ||
install(LocalVue) { | ||
LocalVue.mixin({ | ||
beforeCreate() { | ||
const { | ||
vuex = {}, | ||
methods = {}, | ||
computed = {}, | ||
} = this.$options | ||
|
||
const { | ||
state = {}, | ||
getters = {}, | ||
mutations = {}, | ||
actions = {}, | ||
} = vuex | ||
} | ||
}) | ||
} | ||
} | ||
|
||
Vue.use(plugin) | ||
``` | ||
|
||
Next step is to destructure the `state`, `getters`, `mutations` and `actions` from the `vuex` property and set default objects as well. | ||
|
||
#### Step 3 - Map vuex | ||
|
||
```js | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So, this is all good, but there's no real use case you're covering here. Without a real use case, it's tough for the reader to understand how this is useful. I like what you have- no need to change that, but we do ask for an actual example to bring the cookbook to life and out of just a conceptual model. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cool thanks, so you mean a demo of something correct? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I have a really good real-world use case that I can add to the cookbook, I will update it :) |
||
import Vue from 'vue' | ||
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex' | ||
|
||
const plugin = { | ||
install(LocalVue) { | ||
LocalVue.mixin({ | ||
beforeCreate() { | ||
const { | ||
vuex = {}, | ||
methods = {}, | ||
computed = {}, | ||
} = this.$options | ||
|
||
const { | ||
state = {}, | ||
getters = {}, | ||
mutations = {}, | ||
actions = {}, | ||
} = vuex | ||
|
||
this.$options.methods = { | ||
...methods, | ||
...mapMutations(mutations), | ||
...mapActions(actions), | ||
} | ||
|
||
this.$options.computed = { | ||
...computed, | ||
...mapState(state), | ||
...mapGetters(getters), | ||
} | ||
} | ||
}) | ||
} | ||
} | ||
|
||
Vue.use(plugin) | ||
``` | ||
|
||
This step is the most important as we now need to override and destructure all the vuex mappings to `methods` and `computed` properties. We need to destructure `methods` and `computed` so we don't break existing options that the user exports. | ||
|
||
#### Step 4 - Import plugin | ||
|
||
If you want to use the Vue plugin, we can just import the plugin in your `main.js` file or any entry point file of your Vue app | ||
|
||
```js | ||
import Vue from 'vue' | ||
import './plugins/vuex.js' | ||
|
||
new Vue({ | ||
// options | ||
}).$mount('#app') | ||
``` | ||
|
||
## Creating a NPM package | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great :) |
||
|
||
Creating a NPM package is a bit out of the scope of this cookbook but I believe it is a very important part of making a plugin. I would highly recommend you check out this article on how to create a package [How to make a beautiful, tiny npm package and publish it](https://www.freecodecamp.org/news/how-to-make-a-beautiful-tiny-npm-package-and-publish-it-2881d4307f78/). | ||
|
||
In this case all we would need to do is export the `plugin` object in it's own JS file. | ||
|
||
## Alternative solutions | ||
|
||
In this specific case we just needed to use a mixin, so why don't we just use a mixin instead? We could do that as an alternative solution but what if we want to include `directives` or `filters` globally and make this example a helper plugin for Vue. In most cases users feel more comfortable with plugins as using custom packages is more likely to be registered with `Vue.use()` | ||
|
||
## Wrapping up | ||
|
||
Creating Vue plugins has always seemed like something that was not as approachable to just about any developer but once you really dig into it you will see that it is not that hard and just takes some playing around to understand what's happening under the hood. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice intro :)
The idea could be carried through the sentence to be a little more clear:
Vue exposes a really nifty API for creating plugins, which allow us to modify and add features.