GithubHelp home page GithubHelp logo

pearofducks / mount-vue-component Goto Github PK

View Code? Open in Web Editor NEW
105.0 4.0 10.0 101 KB

a tiny utility to programatically create and mount Vue 3 components (e.g. a Vue.extend replacement)

License: MIT License

JavaScript 100.00%
vue-3 extend component

mount-vue-component's Introduction

mount-vue-component

install

yarn add mount-vue-component

use

import { mount } from 'mount-vue-component'
import { h } from 'vue'

const comp = {
  props: ['name'],
  setup: (props) => () => h('h1', `Hello, ${props.name}!`),
  unmounted() { console.log("Bye") },
  mounted() { console.log("Hi") }
}
const { vNode, destroy, el } = mount(comp, { props: { name: 'world' } })

api

mount(component, { props, children, element, app })

  • component: required, the component to be created/mounted
  • props: props to be passed onto the component, this can include HTML attributes like id or class
  • children: components to be rendered as children of component
  • element: if specified, the element to mount the component into, if not specified, a div will be created
  • app: the Vue app instance from createApp, if provided will be bound to the component's appContext
returns { vNode, destroy, el }
  • vNode: the instance of the component provided
  • destroy: a function that will unmount and destroy the component
  • el: will provide the HTML element the component is mounted into

mount-vue-component's People

Contributors

pearofducks avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

mount-vue-component's Issues

How to pass as argument a globally-defined component imported from a third party package?

Hi, I'm trying to use this neat utility with the component provided by that plugin: https://github.com/highlightjs/vue-plugin. That component is imported thus:

import hljsVuePlugin from '@highlightjs/vue-plugin'
app.use(hljsVuePlugin)

My issue is that when doing const { vNode, destroy, el } = mount(comp, { props: { name: 'world' } }), comp must be defined but if I replace comp with hljsVuePlugin Vue complains that hljsVuePlugin is not defined. Any idea how to solve this issue?

Also I have a hard time understanding how to pass values for the children, element and app arguments. Could you give a complete example where all those things are passed to the mount() function please? Thanks!

HMR handling (vite)

Yo Im using this package for an experiment, it works great. Wondering if there's anything we can do for it to handle HMR?

For example, using this to open dialogs/modals... changing the theme of the main app instance doesnt change the mounted component using this module since it only attaches appContext under the hood.

any help would be much appreciated!

How to apend to some element?

Hi, tanks for the great code , been looking for this for 2 days.
I managed to get it working by this

    const { vNode, destroy, el } = mountComponent(BaseToast);
    container.appendChild(el?.childNodes[0] as Node);

Is this the correct approach ? container is just a plain element.

Usage with appendChild

This example taken from here. I've used this technique successfully in Vue 2 but cannot seem to get it to work with this package.

import Button from 'Button.vue'
import Vue from 'vue'
var ComponentClass = Vue.extend(Button)
var instance = new ComponentClass({
    propsData: { type: 'primary' }
})
instance.$mount() // pass nothing
this.$refs.container.appendChild(instance.$el)

As I understand the design, this should work.

import Button from "./components/Button.vue";
import { mount } from "mount-vue-component";

import { ref, defineComponent, onMounted } from "vue";

export default defineComponent({
  name: "App",
  setup(props, context) {
    const container = ref(null);

    onMounted(() => {
      console.log(container.value);
      var instance = mount(Button, { props: { type: "primary" } });
      container.value.appendChild(instance);
    });
    return { container };
  },
});

reproduction case

Can this mount vuetify and/or custom Vue Components?

I have a custom wrapper around a Vuetify vCard - I can't seem to figure out how to get it mounted using this module - is that even possible? Or will it only do standard Vue components?

I import the custom component, define it, but when trying to mount it:

image

Any help is welcome, I might just be doing something stupid - if this can be done, can you provide a simple sample of how to mount a custom component? Thanks!

Allow prop type to be inferred

Hey, I tried to create PR, but I failed, no access. Maybe I am too dumb to do it properly xD

Here's a suggestion to improve your TS:

export function mount<TProps>(component: Component, { props, children, element, app }?: {
    props?: TProps;
    children?: unknown;
    app?: App;
    element?: HTMLElement;
}): MountResult;

Solves the following issue:
Screenshot 2022-06-10 at 12 29 45

And allows the props to be dynamically infered by TS, no need to pass any additional interfaces:

with infer:
Screenshot 2022-06-10 at 12 38 10

without infer:
Screenshot 2022-06-10 at 12 38 29

API change?

Not sure if there's a valid usecase for passing slots onward - maybe change so the vNode is a normal arg and the rest is an options object.

Can't get a reference to the mounted element

I'm on Vue 3.2.31 and for some reason I can't get a reference to the freshly mounted element.

I have a ConfirmModal component which exposes a show() method, and it works in pure vue if I drop the component on a page and use a ref to get the instance, I can call the method on my instance.

I'm trying to use this library to instanciate multiple ConfirmModal component from code (from a service/helper) and for some reason I cannot get a reference to the newly mounted component. I can see the Hi in the console, meaning the code gets called, but the component does not appear in the DOM, and I didn't find how to cast vNode into my component to be able to call public methods on them.

One interesting thing : If my component uses a <Teleport> I can see the component appear in the teleport zone, meaning they DO get created. But my problem lies at calling methods on them.

This is how I call the component from my service/helper :

import { mount } from 'mount-vue-component'
import { h } from 'vue'
import ConfirmModal from '@/views/components/ui/confirm-modal.vue';

export const Confirm = {
    danger: () => {
        const comp = {
            props: ['title'],
            setup: (props: any) => () => h(ConfirmModal),
            unmounted() { console.log("Bye") },
            mounted() { console.log("Hi") }
        };

        const { vNode, destroy, el } = mount(comp, { props: { title: 'world' } });

        (vNode as any).show(); // <--- This will crash
    }
};

And this is how I call it:

<button class="btn btn-danger" @click="Confirm.danger('yo inside')">DANGER</button>

What is the proper way to cast vNode to my component class, or where can I find the reference ?

Thanks !

Dynamic props

Hi,
Is there a way to make props reactive, as they would with :prop="..." ?

At least, is there a way to set new prop values and make them trigger a change event ? it seems that vnode.props = {... newProps} doesn't do the trick.

parent property of VNode and Component are not set

Using the mount function will not set the parent property of the VNode and the component. It is possible to adjust the function to set those, however you can only set the parent property of the component after the render function is called. If the parent of the component is required in the setup function this will still result in errors, as the setup will be called during the render function call. An example for when it is required is when using the Provide/Inject-API.

I don't believe this can be solved programatically, but the workaround I found was simply using the builtin <component :is="..."> with the is-prop. I found out, that the is prop will not only take names of registered functions but also components that are not previously registered and render them. This resolved all my problems and is generally easier to use than manually mounting and destroying components.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.