Search code examples
javascriptvue.jsembedweb-componentvuex4

Embedding Vue Apps (or Vue Web Components) in a non Vue web application


I'm very new to Vue and have been given a task of looking at creating some Vue widgets that could be embedded in a couple of existing non Vue legacy web applications. The idea is that we would create a library of these widgets which could be then embedded in either of the legacy applications and eventually we might migrate the entire apps to Vue.

I've been searching for the best way forward and I am a bit confused. I guess these are my questions:

  1. Do I need to be thinking Web Components here or can the widgets be actual Vue applications that we embed somehow?

  2. If the widgets should be created as Web Components is there any difference between using the Vue/web-component-wrapper or the vue-custom-element library?

  3. Whichever option we choose can we make full use of features that you would use in any normal Vue application - Vue router, Vuex for state management etc (and can state be shared across those widgets)?

  4. Would the widgets need to be fully styled or would it be best practice to leave all the styling of the components to the parent app (or a combination of the two)?

I've never done anything like this before (as you can probably tell!) so any guidance or advice or pointers to examples would be appreciated.

** Update **

I found this article which I think is the direction I need to go in https://itnext.io/vuidget-how-to-create-an-embeddable-vue-js-widget-with-vue-custom-element-674bdcb96b97


Solution

  • There are three distinct (but quite similar) cases:

    • web components
      They are supposed to be an encapsulated web fragment. If you want, it's a smarter alternative to <iframe>s. Its main use case (and what it was designed for) is to display ads in a page and guarantee the host can't mess with its internal logic and rendering.

    • custom elements
      These are, simply put, declared and registered custom HTML tags. The advantage of using them is being able to mark them as off-limits in any outer framework, stating: "this custom element is not one of your custom components, treat it as an HTML tag".

    • framework components
      By default, modern JS frameworks (Angular, React, Vue) use this pattern internally: their internal components look like custom elements (case 2). But they are not. They are just internal conventions, without ever making it into the HTML markup output of the app.
      Here's what happens internally: when the template is parsed, if an unknown HTML element is met, the framework assumes it's one of its registered components. If it is, the tag is not rendered. A new instance of that component is created and the tag is replaced with the contents of the component's template (or the result of its render function).
      All of the above frameworks, when running into an unknown html tag that is not a registered custom component will issue a warning along the lines of "hey, did you forget to register this component?". Unless it's registered as a custom element (case 2) - in which case they treat it as as such: an HTML tag.

    Vue handles all of the above with grace. What you choose for your widgets largely depends on context and desired end result.

    Here are the answers to your questions:

    1. Do I need to be thinking Web Components here or can the widgets be actual Vue applications that we embed somehow?

    You shouldn't go with Web Components if you want to be able to style them from the context.

    1. If the widgets should be created as Web Components is there any difference between using the @vue/web-component-wrapper or the vue-custom-element library?

    Yes, there is. @vue/web-component-wrapper produces web components (encapsulated DOM framents).
    vue-custom-elements declares and uses custom elements (custom HTML tags). Their content is HTML markup (not encapsulated). The advantage of using custom elements is being able to inform outer frameworks: don't treat this custom element as one of your own components, it's handled by something else (Vue, in our case). Treat it as HTML markup.

    1. Whichever option we choose can we make full use of features that you would use in any normal Vue application - Vue router, Vuex for state management etc (and can state be shared across those widgets)?

    Yes. Whichever option you choose, you're still using JavaScript (every widget/app has unrestricted access to the entire context). You can also inject dependencies into your widgets, allowing them to communicate (by modifying the same external dependency - a router, a state management module, etc...). This is pretty much the standard mode in which every Vue instance normally operates. In simpler words, a Vue (sub-)component can function without a parent component and is, essentially, a Vue app. (or, if you prefer, every Vue app is a Vue instance and all of its sub-components are also Vue instances).

    1. Would the widgets need to be fully styled or would it be best practice to leave all the styling of the components to the parent app (or a combination of the two)?

    It's entirely your code design choice. It's easy to scope CSS in Vue. But there are great advantages in styling from above (DRY-er code). Also, having styles coming from context means less CSS rules applying, although that hardly qualifies as a performance issue. Obviously, take into consideration the answer to the first question.