Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create Vue package that imports another component

We are attempting to create a Vue npm package where one component imports another component (a simple example might be - the package contains a generic button component, and a table component that uses my button component for paging). I can import the child component into the parent component and build the package successfully. But when I import and use the parent component (from the package) in an application, the child component content does not display. Skips past it like it isn't there.

I am at a loss.

I am using some very simple components for testing:

<!-- Child Component -->
<template>
    <div id="childElement">Child Component</div>
</template>

<script>
    export default {
        name: "childComponent"
    }
</script>

<style>
    #childElement {
        font-weight: bold;
    }
</style>
<!-- Parent Component -->
<template>
    <div>
        <div id="parentElement">Parent Component</div>
        <child-component></child-component>
    </div>
</template>

<script>
    import ChildComponent from "./ChildComponent.vue";

    export default {
        name: "parentComponent",
        components: {
            ChildComponent
        }
    }
</script>

<style>
    #parentElement {
        font-weight: bold;
    }
</style>

(Edit) Here is my index.js file

import ParentComponent from './components/ParentComponent.vue';
import ChildComponent from './components/ChildComponent.vue';

const install = Vue => {
  Vue.component("ParentComponent", ParentComponent);
  Vue.component("ChildComponent", ChildComponent);
};

export default {
  install
};

export { ParentComponent, ChildComponent };

Usage (in a different app, after a "yarn add ...")

<template>
  <div>
    <div>
      <h1>Testing Section</h1>
      <parent-component></parent-component>
      <h1>End Testing Section</h1>
    </div>
  </div>
</template>

<script>
  import { ParentComponent, ChildComponent } from ...;

  export default {
    name: 'TestApp',
    components: {
      ParentComponent,
      ChildComponent
    }
  };
</script>

And this is what I get on the page:

Testing Section
Parent Component
End Testing Section

Here are some things that I know:

  • The import path in ParentComponent to ChildComponent is correct. If I purposefully change the path to something that doesn't exist, it errors when I try to build.
  • If I import and use ChildElement directly in the app, it works as expected.
  • If I take ParentComponent and ChildComponent and copy them into the app structure, then import them that way (instead of importing them from the package), then ParentComponent displays ChildComponent exactly the way I would expect it to.

I see other packages out there that seem to import components this way, so I think what I'm doing is possible.

I would be grateful for any thoughts anyone has!

(and let me know if it would be helpful if I included anymore code from the project)

UPDATE I've tracked this down a little more. When I include the child component, I'm getting this warning from the app:

[Vue warn]: resolveComponent can only be used in render() or setup().

which has helped me find other resources on the internets, but nothing has helped. My simple tests aren't explicitly using resolveComponent anywhere. And if I do use it and a render function instead of a template, same result, same warning.

like image 450
KiwiDB Avatar asked Nov 11 '20 04:11

KiwiDB


People also ask

How do I import a component into another component Vue?

You need to create your portfolio component first e.g. in src/components/Projects/Portfolio. vue and then import it inside the script tag within your Landing.

How do I import Vue component into Vue component?

STEP 01: First, Import the Child Component into the Parent Component inside script tag but above export default function declaration. STEP 02: Then, Register the Child Component inside the Parent Component by adding it to components object. STEP 03: Finally, Use the Child Component in the Parent Component Template.


Video Answer


2 Answers

After some rather exhaustive googling and experimentation, I believe the problem you are seeing has to do more with how imported packages work when added from a local folder (pre-published to npm or not added from npm) versus packages that are added via npm or yarn.

The biggest clue to figure this out was the two instances of Vue, which triggers the error in your update.

[Vue warn]: resolveComponent can only be used in render() or setup().

Running down that error, was not so much helpful in and of itself, however, the information that it is happening due to two Vue instances (like you also mentioned finding), was key. It seems that this occurs with local implementations of npm packages. So the solution is to do one or a combination of the following:

A) Find a testing workflow for use in the development of the package that doesn't require you to install the package in a traditional sense and instead import it from a local folder that lives outside of your testing area. Or, build your testing/docs app into your package repo. This way you can build normally without version bumping every little change and only publish and bump versions when you are truly ready.

Then test the usage of your package with a full install from the published npm source as a separate step only after you publish each new version.

B) Locally publish your file using npm pack or yarn pack. This will create a .tgz file. You can use it in your project by adding/installing it from the local path. npm install local-path-to\your-cool-package.tgz or yarn add local-path-to\your-cool-package.tgz. This comes with the caveat that for every change you want to see in your testing app, you will have to remove and re-install it pointing to the new version bump it will append to your file name. You can't simply save and publish to that same file to see updates. You have to bump each change.

Obviously, this is a bit of a clunky workflow, but it works. Perhaps it could be a medium step between a full publish to npm to test a build change. But it seems like, to me anyway, not having worked on packages much personally, that A is a slightly better workflow than B.

Here are some related posts that explain more about similar duplicate Vue with npm install/link/pack and how they work differently for local packages:

Bundling a plugin with Rollup but having duplicate Vue.js package imported in the client app's bundle (Nuxt)

Difference between npm link x and npm install /path/to/x

like image 185
innerurge1 Avatar answered Sep 30 '22 04:09

innerurge1


First, you should check your console if there are any errors.

Also this flat import looks weird import { ParentComponent, ChildComponent } from ...; If you already imported the child component in the Parent, then no need to import again.

I don't know what do you have in your index.js of your package. but I can recommend it to be something like this:

import ParentComponent from './components';
 
export default ParentComponent;

Then, you can use it this way: import ParentComponent from 'NameOfYourNpmPackage'

like image 30
MohKoma Avatar answered Sep 30 '22 05:09

MohKoma