vuejs / composition-api

Composition API plugin for Vue 2
https://composition-api.vuejs.org/
MIT License
4.19k stars 342 forks source link

Cannot import Vue Plugin using Composition API in my project #372

Closed Warz closed 4 years ago

Warz commented 4 years ago

A project and a plugin. The plugin contains Composition API functions that I want to consume in my project. My project is using Composition API already.

But, I can't figure out a way to import plugin in my project successfully. What I present below is the closest I've gotten. The script seems to work (?), but it's throwing warnings such as this; [Vue warn]: The setup binding property "multiTree" is already declared.

index.js (in project)

import Vue from 'vue'
import VueCompositionApi from '@vue/composition-api';
Vue.use(VueCompositionApi);

import { VJstree } from 'vue-jstree-extended'

Vue.use(VJstree,{});

import App from './App.vue'
new Vue({
    el: '#app',
    render: h => h(App)
})

index.js (in plugin)

import VJstree from './tree.vue'
import useMultiTree from "./useMultiTree";
import useTreeActions from "./useTreeActions";
import VueCompositionApi from '@vue/composition-api'; // <---- get rid of this line

VJstree.install = function(Vue,options = {}){
  Vue.use(VueCompositionApi); // <---- get rid of this line
  Vue.component(VJstree.name, VJstree);
};

if (typeof window !== 'undefined' && window.Vue) {
  window.Vue.use(VJstree);
}

export { VJstree, useMultiTree, useTreeActions }

If I remove Vue.use(VueCompositionApi); from plugin, I will get this error in my project: Error in data(): "Error: [vue-composition-api] must call Vue.use(plugin) before using any function."

This doesn't make sense to me. I already called Vue.use(VueCompositionApi) in my project. The line shouldn't be required inside of plugin. Right?

Please note that the plugin is located in another folder, and I'm including it like this: "vue-jstree-extended": "file:../jstree-extended-warz/vue-jstree"

(I've also attempted using npm link, makes no difference)

I've read similar issues: #228 #340 #356 #181 which led me to discover peerDependencies, I've set up Composition API as a peerDependency in plugin.

I've also attempted to import both Vue and Composition API in the plugin, this results in the following error in project while performing actions in the tree: vue.esm.js:629 [Vue warn]: You may have an infinite update loop in a component render function.

So the question is really, how can I get rid of Vue.use(VueCompositionApi) from my plugin?

Any ideas?

pikax commented 4 years ago

This doesn't make sense to me. I already called Vue.use(VueCompositionApi) in my project. The line shouldn't be required inside of plugin. Right?

You don't need to do it in the plugin, using it in the plugin might cause some difficult to spot issues.

Please note that the plugin is located in another folder, and I'm including it like this: "vue-jstree-extended": "file:../jstree-extended-warz/vue-jstree"

The issue is here.

When you are using composition API you need to guarantee you are using the same plugin instance! Usually your bundler will just resolved it easily in your node_modules, but when you link or import from a local folder, your imported node_modules takes priority than your project, if @vue/composition-api is installed there it will use that instance, making you have two different composition-api plugins.

Warz commented 4 years ago

Instance? Or do you mean version? I'm pretty confused right now. I have the same version of Composition API across the board and there should only be one instance set in Vue, it's being set in my project.

Right now I'm only running Vue.use(VueCompositionApi) inside the project and that results in this error: Error: [vue-composition-api] must call Vue.use(plugin) before using any function

I even tried to delete node_modules folder from my plugin (vue-jstree), no dice.

How do I go about fixing this? I need to be able to do local development so I can quickly test changes I make in my plugin.

antfu commented 4 years ago

Hi @Warz , can you share a minimal reproduce repo (best in codesandbox) so we can better help your problem? Thanks.

Warz commented 4 years ago

I hope this is simple enough: https://github.com/Warz/issue372

See instructions in README.md.

I wasn't sure how I'd do this in codesandbox.

After setup you can find this file and remove line 4 and 8

pikax commented 4 years ago

image

seems to be working to me, I'm using yarn

EDIT: Not working with npm

EDIT2: has I said is because there's two instance of composition-api running, you can easily test by:

If only 1 instance is running it should output either one of those logs, but is logging both:

image

This has to do on how the npm resolves the dependencies, plugin node_modules has priority over project node_modules when trying to resolve the dependency in the project

Warz commented 4 years ago

Yes, you are correct. I have not tried yarn, but i'd really like to make this work with npm as well.

The only place importing composition api is in the functions, for example here is useMultiTree.js from the plugin

import { reactive } from '@vue/composition-api';

export default function useMultiTree() {

    const state = reactive({
        currentDraggedNode : null,
    });

    function setDraggedNode(node) {
        state.currentDraggedNode = node;
    }

    function isDragging() {
        return !!state.currentDraggedNode;
    }

    return {
        state,
        isDragging,
        setDraggedNode
    }
}

If I comment out the import line from useMultiTree.js and useTreeActions.js I'm not getting the console.log output for the plugin composition api node_modules, but obviously that breaks the functions.

Any idea how I would go about fixing this? I tried setting resolve alias in the project webpack to force it to use the one in my project:

    resolve: {
        symlinks: false,
        alias: {
            '@vue/composition-api': path.resolve(path.join(__dirname, '../node_modules/@vue/composition-api/'))
        }
    }

but didn't make any difference.

Maybe there's some documentation detailing this specific issue?

pikax commented 4 years ago

That's a module resolver issue , either webpack or npm, the solution for this problem is making sure you only import the same @vue/composition-api, how you can do it is quite dependent on the tools you use. Unfortunately I don't know how to achieve that with webpack and npm (with localImport)

I'm surprised yarn worked.

If you find a solution please share here.

darrenjennings commented 4 years ago

I tried setting resolve alias in the project webpack to force it to use the one in my project:

@Warz FWIW your alias resolve fixed it for me. my vue.config is is in the same dir as my node_modules btw

- '@vue/composition-api': path.resolve(path.join(__dirname, '../node_modules/@vue/composition-api/'))
+ '@vue/composition-api': path.resolve(path.join(__dirname, './node_modules/@vue/composition-api/'))
Warz commented 4 years ago

I'm using webpack, changing to that just results in error Module not found: Error: Can't resolve '@vue/composition-api'

Can you post full code?

antfu commented 4 years ago

BTW, have a look at vue-demi :)

Warz commented 4 years ago

Thanks for fix. I've upgraded to 1.0.0-beta.2, but now I'm getting some different errors: chrome_2020-07-05_23-18-18

Any ideas? Do I need to do any specific changes to make it work?

antfu commented 4 years ago

Can you update your code to the repo and share again? Thanks

Warz commented 4 years ago

I've now comitted the latest changes

Running npm run build in the plugin folder and npm run dev in the project folder

ymchun commented 4 years ago

Thanks for fix. I've upgraded to 1.0.0-beta.2, but now I'm getting some different errors: chrome_2020-07-05_23-18-18

Any ideas? Do I need to do any specific changes to make it work?

I have the same issue when using composition api in my plugin and imported to my project. It works without any problems when the plugin components are stay within the same project.

Suspect the issue is due to different instance of composition api. The following code is how I export the plugin inside index.ts

import { VueConstructor } from 'vue'

import ColumnSectionItem from './components/column-section-item.vue'
import DynamicForm from './components/dynamic-form.vue'
import RowSectionItem from './components/row-section-item.vue'

export default {
  install(_vue: VueConstructor) {
    _vue.component('ColumnSectionItem', ColumnSectionItem)
    _vue.component('DynamicForm', DynamicForm)
    _vue.component('RowSectionItem', RowSectionItem)
  },
}

package dependencies

"dependencies": {
    "@u3u/vue-hooks": "^2.0.1",
    "@vue/composition-api": "^1.0.0-beta.2",
    "core-js": "^3.6.5",
    "vue": "^2.6.11",
    "vue-router": "^3.2.0",
    "vuetify": "^1.5.24",
    "vuex": "^3.4.0"
},
antfu commented 4 years ago

@Warz you are packing @vue/composition-api into your plugin - which you shouldn't. Closing for now. Thanks

Warz commented 4 years ago

@Warz you are packing @vue/composition-api into your plugin - which you shouldn't. Closing for now. Thanks

What do you mean? I've set it as a peer dependency?

antfu commented 4 years ago

https://webpack.js.org/configuration/externals/

Warz commented 4 years ago

Like this ? *

  module.exports.externals = {
      '@vue/composition-api': 'commonjs2 @vue/composition-api'
  }

Doing that put me back at this point:

vue.runtime.esm.js:620 [Vue warn]: Error in data(): "Error: [vue-composition-api] must call Vue.use(VueCompositionAPI) before using any function."

found in

---> <App> at src/App.vue
       <Root>
ymchun commented 4 years ago

Like this ? *

  module.exports.externals = {
      '@vue/composition-api': 'commonjs2 @vue/composition-api'
  }

Doing that put me back at this point:

vue.runtime.esm.js:620 [Vue warn]: Error in data(): "Error: [vue-composition-api] must call Vue.use(VueCompositionAPI) before using any function."

found in

---> <App> at src/App.vue
       <Root>

in your vue.config.js you can refer to my repo: https://github.com/ymchun/vue-dynamic-form

module.exports = {
  chainWebpack: config => {
    config.merge({
      externals: ['vue', '@vue/composition-api'],
    })
  },
}
oneMoreTime1357 commented 3 years ago

add '@vue/composition-api' to webpack externals solve my problem;

xieqian423 commented 3 years ago

image 编译后报错[vue-composition-api]no vue dependency found