Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for How to migrate your library from Vue2 to Vue3
Alvaro Saburido
Alvaro Saburido

Posted on • Edited on • Originally published atalvarosaburido.dev

     

How to migrate your library from Vue2 to Vue3

Vue 3 is just around the corner. The hype is real so you might be tempted to start migrating all your existing projects to the new version. Before doing that I will save you some pain with this simple question:

Does your app heavily depends on third party libraries like (BootstrapVue, Vuetify, etc)?

If the answer is yes, you might want to stop the process for a moment.

Why?

Most of Vue plugins and third-party libraries will not work on Vue3 (yet) due to the breaking changes on theGlobal APIsee reference.

Vue contributor@posva stated in thisgithub thread:
@posva github comment

In this article, I will show you how to migrate a Vue 2.x library to Vue 3.x plugin, so if you are the owner of a library or just a user that wants to contribute to your favorite carousel plugin to migrate to Vue3 this tutorial is for you.

The new global API

One of the major breaking changes introduced on Vue 3.x is how the app is created:

In2.x global APIs and configurations globally mutate Vue's behavior

// main.jsimportVuefrom'vue';importAppfrom'./App.vue';newVue({render:h=>h(App),}).$mount('#app');
Enter fullscreen modeExit fullscreen mode

For instance, you want to addvue-toasted library into your project, you would useVue.use and pass the library object with the options:

// main.jsimportVuefrom'vue';importVueToastedfrom'vue-toasted';Vue.use(VueToasted,{...options});
Enter fullscreen modeExit fullscreen mode

Under the hood, whatVueToasted does, extends the Vue instance and declare some components (Vue.component) and global objects into it (Vue.prototype):

// vue-toasted/src/index.jsconstToasted={install(Vue,options){if(!options){options={};}constToast=newT(options);Vue.component('toasted',ToastComponent);Vue.toasted=Vue.prototype.$toasted=Toast;},};
Enter fullscreen modeExit fullscreen mode

In 3.x the app instance is created troughcreateApp:

// main.jsimport{createApp}from'vue';importAppfrom'./App.vue';constapp=createApp(App);
Enter fullscreen modeExit fullscreen mode

An app instance exposes a subset of the current global APIs. The rule of thumb is any APIs that globally mutate Vue's behavior are now moved to the app instance like this

constapp=createApp(App);app.component('button-counter',{data:()=>({count:0,}),template:'<button @click="count++">Clicked {{ count }} times.</button>',});app.directive('blur',{mounted:el=>el.blur(),});
Enter fullscreen modeExit fullscreen mode

So you might be tempted to do:

constapp=createApp(App);app.use(VueToasted,{...options});
Enter fullscreen modeExit fullscreen mode
Uncaught TypeError: Cannot set property '\$toasted' of undefined
Enter fullscreen modeExit fullscreen mode

Why? Because in thevue-toasted library the property is added to 'Vue':Vue.toasted = Vue.prototype.$toasted = Toast;

The Solution

Actually, is pretty simple, let's remove the oldplugin/index.js and create a plugin object:

constVueToastedPlugin={install(app,options){if(!options){options={};}constToast=newT(options);app.component('toasted',ToastComponent);app.config.globalProperties.$toasted=Toast;},};exportdefaultVueToastedPlugin;
Enter fullscreen modeExit fullscreen mode

You may notice two subtle changes:

  1. app instance is passed as a parameter of the install method, so now instead of doingVue.component we doapp.component
  2. To add a global property,Vue.prototype becomesapp.config.globalProperties

Now, you will be able to useapp.use(VueToasted, {...options});. In the specific case ofvue-toasted library you will normally create a new toasted message accesing the$toasted onthis:

methods:{showToast(){this.$toasted.show('How you doing?');}}
Enter fullscreen modeExit fullscreen mode

With Composition API

So we manage to take a random Vue library without Vue 3.x support into the new standard. The previous code will work perfectly with the options API but what about using it along of one of the most interesting and new features of Vue3, the composition API?

Yes,this is not accesible in thesetup() method, a lot of libraries today inject properties ontothis. Let's take another example,Vue Router injectsthis.$route andthis.$router, andVuex injectsthis.$store.

When using the Composition API, since there is nothis. Plugins will leverageprovide andinject internally and expose a composition function. Let's continue usingvue-toasted as an example:

// useApi.jsimport{inject}from'vue';exportconstVueToastedSymbol=Symbol();exportfunctionuseToasted(){constVueToasted=inject(VueToastedSymbol);if(!VueToasted)thrownewError('No VueToasted provided!!!');returnVueToasted;}
Enter fullscreen modeExit fullscreen mode

then we provide into the app instance -->app.provide(VueToastedSymbol, Toast);

import{ToastedasT}from'./js/toast';importToastComponentfrom'./toast.vue';import{VueToastedSymbol}from'./useApi';export*from'./useApi';constVueToastedPlugin={install(app,options){if(!options){options={};}constToast=newT(options);app.component('toasted',ToastComponent);app.config.globalProperties.$toasted=Toast;app.provide(VueToastedSymbol,Toast);},};exportdefaultVueToastedPlugin;
Enter fullscreen modeExit fullscreen mode

So now, in any setup method or composition function we can do:

import{useToasted}from'vue-toasted`;const Component = {  setup() {    const toasted = useToasted();    toasted.success('CompositionAPIBABYYY!', {      position:'bottom-right',      duration: 5000,    });  },};
Enter fullscreen modeExit fullscreen mode

Conclusion

You might be thinking, why the plugin authors are not doing this already 🤔? Most of the core libraries likeVue-router andVuex already have a/next branch and beta releases with the support for vue3 and even with Typescript as default but the rest of third party libraries are open source, and believe, is hard to keep your library updated by your own(we have limited hours per day) without contribution for other developers.

So, did you find out the awesome library you were working with for your toast message isn't working for vue3? Make a PR like I didhere to the library with the stuff you learn today. Not only it will be highly appreciated by the authors of the plugin but also will give you a higher level of knowledge in Vue. You will contribute to the community 😊.

GitHub logo WIP: new global api install + composition provide + update deps#180

Hello,

This PR is meant for migrating the library to be used in Vue 3.x (is in Work in Progress), the PR set to basemaster but it should be aiming to a/next branch on the base@shakee93 so both2.x and3.x solutions coexist in the same repo. If this branch is created I will change the destination of the PR

Basic changes:

vue-toasted/index.js :

import{ToastedasT}from'./js/toast';importToastComponentfrom'./toast.vue';import{VueToastedSymbol}from'./useApi';export *from'./useApi';constVueToastedPlugin={install(app,options){if(!options){options={};}constToast=newT(options);app.component('toasted',ToastComponent);app.config.globalProperties.$toasted=Toast;app.provide(VueToastedSymbol,Toast);},};exportdefaultVueToastedPlugin;
Enter fullscreen modeExit fullscreen mode

Now instead of Vue, theapp instance is passed so it will work with the newcreateApp, and the global property will be available onthis by usingapp.config.globalProperties.$toastedreference

constapp=createApp(App);app.use(VueToasted,{ ...options});
Enter fullscreen modeExit fullscreen mode

In Vue 3.x plugins will leverageprovide andinject internally and expose a composition function.

To do that I add auseApi.js for the use of the library along with the Composition APIreference:

// useApi.jsexportconstVueToastedSymbol=Symbol();exportfunctionuseToasted(){constVueToasted=inject(VueToastedSymbol);if(!VueToasted)thrownewError('No VueToasted provided!!!');returnVueToasted;}
Enter fullscreen modeExit fullscreen mode

So now, in any setup method or composition function we can do:

import{useToasted}from 'vue-toasted`;constComponent={setup(){consttoasted=useToasted();toasted.success('Composition API BABYYY!',{position:'bottom-right',duration:5000,});},};
Enter fullscreen modeExit fullscreen mode

To support the last release candidate vue3.0.0-rc.9 I needed to update several packages from the package.json, this is causing errors in the webpack build process, especially with the uglify plugin:

cross-env NODE_ENV=production webpack --config ./build/webpack.release.js --progress --hide-modules/Users/alvarosaburido/as/github/as-vue-toasted/node_modules/webpack-cli/bin/cli.js:93                                throw err;                                ^Error: webpack.optimize.UglifyJsPlugin has been removed, please use config.optimization.minimize instead.    at Object.get [as UglifyJsPlugin] (/Users/alvarosaburido/as/github/as-vue-toasted/node_modules/webpack/lib/webpack.js:189:10)

If someone from the core team is available to help me out with this I think is ready to be used (already tested as a submodule in a personal project).

Feel free to contact me directly if needed.

Happy Coding

That's all folks, keep it rockin'.

That's all folks

Top comments(8)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss
CollapseExpand
 
rchl profile image
Rafał Chłodnicki
  • Joined
  • In theuseApi.js code block you are not showing where theinject function comes from. Maybe worth adding?
  • It looks like the convention for "native" Vue libraries is to use a separate (next) branch to add support for Vue3. Is there anything blocking one from adding support on the existing branch as a new feature?
CollapseExpand
 
alvarosabu profile image
Alvaro Saburido
Creative Software Engineer from 🇻🇪 living in Barcelona, Spain.Developer Experience Engineer at StoryblokAuthor of TresJSContent Creator @AlvaroDevLabsFormer founder of Porsche Digital Bcn.
  • Location
    Barcelona Spain
  • Education
    Telecommunications Engineer
  • Work
    DevRel at Storyblok
  • Joined

Good catch, I will add it, it's important to be added

For the second one yes is good to use "next" branch is also referencing to npm channel next where you can install from a certain tag version . Lets see it with the following practical example

Your library for vue2 is currently on version 1.2.0, you create a branch called next, that is going to be some kind of a "master/develop" branch for the new version, and you start there from 2.0.0, you would do the same git flow as you normally do, create a feature branch, or bugfix from next and merged into next.

That way in the same repo you mantain a 1.x.x version for vue2 and a 2.x.x of the library for vue3. When you feel the next version is ready you can merge it into master so its your stable version of the package.

I would suggest to wait a little to do that, in the meantime suggest your user to install the vue3 compatibility version trough 'npm i your-awesome-lib@next'

I hope it helps, if you have more question feel free to write me, and thanks for the feedback

CollapseExpand
 
peoray profile image
Emmanuel Raymond
Hi, I'm Raymond. I love JavaScript
  • Joined

Thanks for the article:)

I have some follow-up questions:

  • Does that mean all you have to do to migrate an existing library is to do as the article suggest? Is there something else to do when migrating (I'm assuming you have to update some dependencies like Vue from 2.x.x to 3.x.x)?

  • Can I also use the next version the same way as the main version? Say I install the @next version but don't want to use it with composition API, will this work?

Thread Thread
 
alvarosabu profile image
Alvaro Saburido
Creative Software Engineer from 🇻🇪 living in Barcelona, Spain.Developer Experience Engineer at StoryblokAuthor of TresJSContent Creator @AlvaroDevLabsFormer founder of Porsche Digital Bcn.
  • Location
    Barcelona Spain
  • Education
    Telecommunications Engineer
  • Work
    DevRel at Storyblok
  • Joined

Hello Emmanuel, thanks for reaching out

  1. Yes, you have to update vue to 3.x version, and all related dependencies. This article covers adapting the installation of the plugin to the new standard in vue 3.
  2. Composition API is purely additive, so the library would work exactly the same if use with the Options API. It does depends if they're more breaking changes other than the installation added by the authors. In that case they should be reflected in a proper "Migration Guide" in the documentation.

I hope this clarifies your doubts. If you have any other, feel free to ask.

Happy coding.

Thread Thread
 
peoray profile image
Emmanuel Raymond
Hi, I'm Raymond. I love JavaScript
  • Joined
• Edited on• Edited

Thanks for your reply. This reason I ask is that I'm planning on making a package and from what I have read, I can just go ahead and use the new standard and it will work for both Vue 2 and Vue 3, yeah?. This is what I need clarification on.

SinceVue.component isn't available for plugin in Vue 3, if I useapp.component as you showed in the article and someone using Vue 2.x.x installs my package and then call it withVue.use(packageName) in theirmain.js, will this process work?

CollapseExpand
 
zuo305 profile image
John zuo
Angular
  • Location
    Sydney
  • Work
    Full stack dev at PTC
  • Joined

Hi Alvaro, Thanks for your article. I am wondering what is the "plugin/index.js", how can I update it. I found there is a new branch on github. But I do not know how to update the lib with the "next" branch? Thanks for your time to read this.

CollapseExpand
 
denrique88 profile image
denrique88
  • Joined

Hi !

I'm learning Vue and I started a personal project using Vue 3.0.
Many libraries are not ready to use with Vue 3, so I was interested by your article. Thank you ! I wanted to test your changes in Toasted in my project.
So I installed Toasted with npm targeting the github repo on #next branch.

Unfortunately, I wasn't able to do it work.
When adding Toasted in my main.js file :

import Toasted from 'vue-toasted';const app = createApp(App);app.use(store).use(router).use(Toasted).mount('#app');

I get an error in the console :

Uncaught TypeError: t.prototype is undefined    install vue-toasted.min.js:1    use runtime-core.esm-bundler.js:3164

Maybe I'm doing something wrong or misunderstanding... do you have an idea of why this error is happening ?

Thank you !

CollapseExpand
 
alvarosabu profile image
Alvaro Saburido
Creative Software Engineer from 🇻🇪 living in Barcelona, Spain.Developer Experience Engineer at StoryblokAuthor of TresJSContent Creator @AlvaroDevLabsFormer founder of Porsche Digital Bcn.
  • Location
    Barcelona Spain
  • Education
    Telecommunications Engineer
  • Work
    DevRel at Storyblok
  • Joined

Hey!

Even if I did the PR to vue-toasted library and was merged, I think they haven't finished migrating for support of vue3 yet, I would suggest opening a ticket heregithub.com/shakee93/vue-toasted/is...

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

Creative Software Engineer from 🇻🇪 living in Barcelona, Spain.Developer Experience Engineer at StoryblokAuthor of TresJSContent Creator @AlvaroDevLabsFormer founder of Porsche Digital Bcn.
  • Location
    Barcelona Spain
  • Education
    Telecommunications Engineer
  • Work
    DevRel at Storyblok
  • Joined

More fromAlvaro Saburido

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp