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

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

Closed
Warz opened this issue Jun 12, 2020 · 21 comments · Fixed by #427
Closed

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

Warz opened this issue Jun 12, 2020 · 21 comments · Fixed by #427
Assignees

Comments

@Warz
Copy link

Warz commented Jun 12, 2020

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
Copy link
Member

pikax commented Jun 12, 2020

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.

@antfu antfu added the documentation Improvements or additions to documentation label Jun 12, 2020
@Warz
Copy link
Author

Warz commented Jun 12, 2020

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
Copy link
Member

antfu commented Jun 12, 2020

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

@Warz
Copy link
Author

Warz commented Jun 12, 2020

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
Copy link
Member

pikax commented Jun 12, 2020

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:

  • open /plugin/node_modules/@vue/composition-api/dist/vue-composition-api.module.js
    • on the second line add: console.log('composition-api instance from "plugin"')
  • open /project/node_modules/@vue/composition-api/dist/vue-composition-api.module.js
    • on the second line add: console.log('composition-api instance from "project"')

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
Copy link
Author

Warz commented Jun 13, 2020

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
Copy link
Member

pikax commented Jun 13, 2020

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
Copy link

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/'))

@antfu antfu closed this as completed Jun 23, 2020
@Warz
Copy link
Author

Warz commented Jun 23, 2020

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 antfu reopened this Jun 23, 2020
@antfu
Copy link
Member

antfu commented Jul 4, 2020

BTW, have a look at vue-demi :)

@Warz
Copy link
Author

Warz commented Jul 5, 2020

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
Copy link
Member

antfu commented Jul 6, 2020

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

@Warz
Copy link
Author

Warz commented Jul 6, 2020

I've now comitted the latest changes

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

@antfu antfu reopened this Jul 7, 2020
@antfu antfu self-assigned this Jul 7, 2020
@antfu antfu removed the documentation Improvements or additions to documentation label Jul 7, 2020
@ymchun
Copy link

ymchun commented Jul 10, 2020

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
Copy link
Member

antfu commented Jul 10, 2020

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

@antfu antfu closed this as completed Jul 10, 2020
@Warz
Copy link
Author

Warz commented Jul 10, 2020

@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
Copy link
Member

antfu commented Jul 10, 2020

@Warz
Copy link
Author

Warz commented Jul 10, 2020

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
Copy link

ymchun commented Jul 11, 2020

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
Copy link

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

@xieqian423
Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants