vuejs / docs

πŸ“„ Documentation for Vue 3
https://vuejs.org
Other
2.91k stars 4.37k forks source link

Custom plugin in Typescript after Vue 3.4 update #2729

Open joaoefornazari opened 7 months ago

joaoefornazari commented 7 months ago

According to Vue 3.4 docs, if I want to define a custom plugin, I need to create it like this:

// my-custom-plugin.ts
export default {
  install: (app, options) => {
    // do something here with app and options
  }
}

Then, on main.ts, I set app to use it:

import App from './App.vue'
import router from './router'
import customPlugin from './my-custom-plugin'

export const app = createApp(App)
app.use(router)
app.use(customPlugin)

And that was OK until I updated Vue to version 3.4.20. I was using 3.2.45 before.

Now, when I try to build the project with yarn build (which uses vite build too) it throws this error:

Argument of type '{ install: (app: App, options: any) => void; }' is not assignable to parameter of type 'Plugin<[]>'.
  Type '{ install: (app: App, options: any) => void; }' is not assignable to type 'FunctionPlugin<[]>'.

After searching for type definitiions in node_modules/@vue/runtime-core/dist/runtime-core.d.ts, I found out that, in order to Typescript doesn't claim any type errors, I must define my plugin as an ObjectPlugin type.

I did it this way:

import { ObjectPlugin } from 'node_modules/@vue/runtime-core/dist/runtime-core'

export default {
  install: (app, options) => {
    // stuff
  },
} as ObjectPlugin

I can't use Plugin type because it says that Plugin type is deprecated.

Is my fix correct? How can I contribute so the Vue docs has some notes regarding Typescript support?

NataliaTepluhina commented 6 months ago

@joaoefornazari have you reached the issue on the core repository? It looks like we might improve the code instead of adding a specific section to docs πŸ€”

joaoefornazari commented 6 months ago

@NataliaTepluhina I'll give a try. This is a thing that never happened to me so I was lost in what to do about it - I thought that there was already something on Vue core that would solve this but people forgot to put it on the docs. That's why I opened the issue.

Maybe I open an issue on vuejs/core? What would you recommend?

brc-dd commented 6 months ago

I can't use Plugin type because it says that Plugin type is deprecated.

Where? There is no deprecation notice for that (https://github.com/vuejs/core/blob/01172fdb777f9a0b51781ed2015a1ba3824340a3/packages/runtime-core/src/apiCreateApp.ts#L168). import type { Plugin } from 'vue' should work fine. Also you should not cast it to Plugin, it should be satisfies Plugin:

import type { Plugin } from 'vue'

export default {
  install(app, options) {

  }
} satisfies Plugin

// or if you're using named exports

export const foo: Plugin = {
  install(app, options) {

  }
}
joaoefornazari commented 6 months ago

I solved the problem that happened with me here.

I did it like this:

export default { install: (app: App, options?: any) => { // stuff using app and options (optional) }, } satisfies Plugin


- `main.ts`

import App from './App.vue' import router from './router' import customPlugin from './my-custom-plugin'

export const app = createApp(App) app.use(router) app.use(customPlugin)



Thanks @brc-dd for the clarification!
But still, this solution ain't listed on the docs. @NataliaTepluhina Shouldn't it be there?
os-tohe commented 4 months ago

I have the exact same problem and the above solution did not work for me. I am using Vue version 3.4.26. I am creating a component library. The plugin works fine when I use it directly in my component library, but when I export the plugin and try to use it in another project it throws these errors:

Argument of type '{ install: (app: App<any>) => void; }' is not assignable to parameter of type 'Plugin<[]>'.
  Type '{ install: (app: App<any>) => void; }' is not assignable to type 'FunctionPlugin<[]>'.
    Type '{ install: (app: App<any>) => void; }' is not assignable to type '(app: App<any>) => any'.
      Type '{ install: (app: App<any>) => void; }' provides no match for the signature '(app: App<any>): any'.ts(2345)
chriscdn commented 3 months ago

I had this issue with v3.4.16, but upgrading to v3.4.29 resolved it.

dmoczisko commented 3 months ago

I'm also seeing this error when bumping to vue version ^3.4.30. Most recent working version is 3.4.25 - Variations of the solutions above do not resolve the problem.

brc-dd commented 3 months ago

Do any of you have a minimal, reproducible example? Also the code in https://github.com/vuejs/docs/issues/2729#issuecomment-2023953841 is not exactly correct, if you're saying something satisfies Plugin, you don't need type parameters on individual arguments, certainly not two commas and any.

Also it doesn't seem like a docs issue. If you're not able to make something work, a better place to ask might be on https://chat.vuejs.org. In the docs, we can just add a short sub section at https://vuejs.org/guide/reusability/plugins.html#writing-a-plugin showing how to use it with typescript. Basically, something like the equivalent of JS example there:

// plugins/i18n.ts
import type { Plugin } from 'vue'

export default {
  install: (app, options) => {
    // Plugin code goes here
  }
} satisfies Plugin
joaoefornazari commented 3 months ago

@brc-dd Oh, sorry. I didn't see the comma lost over there. Also, the comma is not on my original code, so no problem at all - but I'll fix the code on the comment.

And also: adding a short subsection on the Writing a Plugin page would be good IMO. I really like how Vue docs takes care of mentioning Typescript typing when it is the case. The Vue docs is one of the easiest and "straightforward-est" docs to read out there, so it really surprised me to discover that I had to find out the correct Typescript approach by myself. I know this situation can sound simple, but it wasn't obvious to me and apparently it wasn't for some other people too.

EDIT: Code fixed.

brc-dd commented 3 months ago

Yeah regarding docs I agree. But the last three comments are probably because of something else. They better be posted on discussions/discord. One is saying it works with v3.4.29 and the other is saying that most recent working version is v3.4.25 -- which are obviously conflicting. If any of those can share a repo where this happens we could probably resolve those.

dmoczisko commented 3 months ago

In my particular case, this issue was as a result of a mismatch in package.json files both referencing vue, but with different versions

luckylark2000 commented 3 months ago

I meet the same problem with v3.4.29 ,but upgrading to v3.4.30 resolved it。by the way, before I upgrading to v3.4.30, I delete the node_modules and pnpm-lock.yaml, then I reinstall the project by pnpm i , maybe this also help πŸ˜„