How to include a Vue app inside another Vue website?

Question

I am building a website using Vue 3 + Vite in an SPA fashion (let’s call this my new Vue website). On this website I have multiple “pages” handled by Vue Router. On one of these pages I want to include another Vue 3 SPA app I have built previously (let’s call this my old app), which is managed and built in a separate project. How can I do this?

Background

Previously, my website was a static site built using Jekyll, and then I could simply put the dist folder of my old app into the directory structure of my jekyll site, ignore the index.html file built by Vue, and include the index.js and index.css files built by vue where I wanted them in my jekyll site. As long as I set the base_url correctly when building my old Vue app, everything worked.

What I’ve tried so far

What I’ve tried so far is to create a component on my new Vue website with a <div id="app"></div> tag. Then I’ve put the dist folder of my old app in the new website’s assets folder, and include the JS/CSS from the old app into the component like so (composition API):

import appJs from "../assets/my-old-app/assets/index.js?url";
import appCss from "../assets/my-old-app/assets/index.css";

onMounted(() => {
  let s = document.createElement("script");
  s.setAttribute("id", "my-old-app-script");
  s.setAttribute("src", appJs);
  document.head.appendChild(s);

  let l = document.createElement("link");
  l.setAttribute("id", "my-old-app-style");
  l.setAttribute("rel", "stylesheet");
  l.setAttribute("innerHtml", appCss);
  document.head.appendChild(l);
});

This manages to include the old app on the new website, but doesn’t work correctly for a couple of reasons:

  1. My old app has images and other assets in /src/assets/my-old-app/assets/, but these are not found when the old app is deployed on the new website. The get requests for these resources goes to http://localhost:3000/my-old-app/assets/, but for this to work the website router would need to serve files at that URL that are actually located in /src/assets/my-old-app/assets/ in the website project.
  2. Including a script like this only works once. If I navigate to another page and back, there are errors because the script has already been defined on the document.

Additional

On my website I actually have more than one old app. For one of them (also built in Vue) I’ve found that it seemed best to put the app dist folder on the backend (I only want to serve it if user is authenticated), and then fetch and show it in an iframe on the frontend. However, for the app I’m asking about here, this would not be ideal since this app should be integrated tightly into the new website. It just makes a lot of sense to continue keeping it in a separate project. (Though, if I can’t find another solution, merging the old app into the new website project might be the second best thing.)

I don’t think you’d ever be able to embed an existing Vue app within another - there’s just so many things that could/should go wrong. Re-renders of the parent app causing the child app to completely re-initialise is the first issue that comes to mind.

The only way I can think of doing this would be to use an iframe so your embedded Vue app is completely in its own sandboxed environment - again, watch out for re-renders.

Hm… thank you for your answer! It makes me wonder if my strategy is a bit off the mark?

Imagine this scenario: You run a news website. All pages on the site has a common navbar, footer and font style. In the navbar are links to News, Weather and Sports sections. Each section is developed by a different team, each with their own routes, components and logic. How would this project be structured? Does it only work to have one giant project that all the teams work on?

What if the Weather team has a bunch of old Vue2 components they want to use? Do they have to rewrite all of them in Vue3 inside the new project?

More background: I develop small web based games. Sometimes an iframe makes a lot of sense, but other times I just want the style of the game to fit the page. Say that I create some kind of quiz: it should just look like a series of forms on the page, but it needs route control to allow users to share their result as a url. Additionally, whenever I develop something new I might want to use a newer framework for that game, or maybe an entirely different framework like React, and still include it on the same website as all my older games. But I also don’t want to upgrade all my older games whenever I need to upgrade framework versions on my website.

I just don’t know what the common ways are for managing something like this.

First, the team needs to build these components in a high level reusable manor. This takes a lot more thought and work to make sure you hit all the use cases you need to, but don’t box yourself in to certain ways of doing things.

Next, you’d likely establish a mono repo for these components as packages that can be imported into your main project(s). This way you have versioned packages and each project can import them at a certain version or at the latest version and upgrading a project is as simple as pulling the latest.

Certainly not, upgrading old code just so it can fit in your website sounds like a nightmare. The best solution I can think of for this is to host each of your apps on seperate domains - by domain I don’t necessarily mean web url domain, but treated as it’s own site, which could be a sub-domain or even sub-directory, e.g. my-site.com/games/my-game

The key is to load the game/app within its own context.

Thank you for giving me your input on this, I really appreciate it! It has definitely helped me get a better perspective on this issue.

I would like to build my overall website in Vue, but as you pointed out, then I need to have some way of presenting each app within its own context, which now that I’ve thought about it, is going to be difficult in an SPA on its own. My old static website is of course doing this by default, since its template engine builds an actual html document for each page. This is nice since it means I can also easily add elements from the parent website (navbar, comments section etc.) around the app.

As such I may have to consider if it actually is worth it to rebuild my site in Vue (though Vue sure is more fun than liquid), or what other ways there are to give each app its own context. The possibilities I see after your suggestions and will consider further are iframes, serving the apps on their own sub-directory but completely separated from the main website, looking into if Vue-based static site generators like Gridsome could be a solution, or possible just a Vue multi-page app could do what I need.

Including a Vue app inside another Vue website is a simple process. First, you need to create a new Vue instance with the desired options. Next, you need to mount the instance to a DOM element. Finally, you need to include the Vue app inside the website.

Hi, thank you! Could you be a bit more specific on how one would do all that?

I would assume that by creating a new Vue instance you mean making another call to createApp()? But then I need to supply it a vue component, which I don’t have if the app I want to include is already compiled.

I have looked into Vue multi-page apps. At least then it is possible to create an html file that loads a different script, so I can use that to load another application. However, there were some problems with it, like routing, that made it not quite the solution I wanted.

My best lead at the moment is https://micro-frontends.org/ which describes how to do this from a general sense. There is some setting up required, so I haven’t gotten around to implementing this pattern yet, but it seems like a promising method for my use case.