I currently render Vue apps into Vue apps. I achieve this by embedding the index.html file of the sub-app into a div container of the main-app.
<template>
<div id="customAppContainer"></div>
</template>
<script>
export default {
mounted() {
this.updateCustomAppContainer();
},
methods: {
updateCustomAppContainer() {
const fullRoute = this.$router.currentRoute.fullPath;
const routeSegments = fullRoute.split("/");
const appsIndex = routeSegments.indexOf("apps");
const appKey = routeSegments[appsIndex + 1];
document.getElementById(
"customAppContainer"
).innerHTML = `<object style="width: 100%; height:100%;" data="http://localhost:3000/subApps/${appKey}"></object>`;
}
},
watch: {
$route(to, from) {
this.updateCustomAppContainer();
}
}
};
</script>
If you want to know more about this please have a look here
mount Vue apps into container of main Vue app
and my own answer to this problem
https://stackoverflow.com/a/58265830/9945420
My sub-app rendered within the object
tags of the customAppContainer
has it own routes, a basic routing would be
export default new Router({
base: '/my-first-custom-app/',
mode: 'history',
routes: [
{
path: '/',
component: PageOne,
},
{
path: '/two',
component: PageTwo,
},
],
});
I can navigate through my sub-app and log the current url
<script>
export default {
created() {
console.log(this.$router.currentRoute.fullPath);
}
};
</script>
On the first route I get /
and on the second one I get /two
. This is correct. But while navigating through the sub-app the browser URL never changes. When calling localhost:3000/apps/my-first-custom-app/two
the fileserver serves the index.html
and is not able to forward to /two
.
Is it possible to forward to the correct route? And manipulate the browser URL when navigating through the sub-app?
Update:
I tried to remove the object tags because they seem to create a blackbox. I found another approach here
https://stackoverflow.com/a/55209788/9945420
The updated code should be
<template>
<div id="customAppContainer"></div>
</template>
<script>
export default {
async mounted() {
await this.updateCustomAppContainer();
},
methods: {
async updateCustomAppContainer() {
const fullRoute = this.$router.currentRoute.fullPath;
const routeSegments = fullRoute.split("/");
const appsIndex = routeSegments.indexOf("apps");
const appKey = routeSegments[appsIndex + 1];
// document.getElementById(
// "customAppContainer"
// ).innerHTML = `<object style="width: 100%; height:100%;" data="http://localhost:3000/subApps/${appKey}"></object>`;
const response = await fetch(`http://localhost:3000/subApps/${appKey}`);
const htmlContent = await response.text();
document.getElementById("customAppContainer").innerHTML = htmlContent;
}
},
watch: {
async $route(to, from) {
await this.updateCustomAppContainer();
}
}
};
</script>
This code works with plain HTML files (no Vue apps) but when I want to embed a distributed Vue app this app is not rendered.
Minimalistic reproduction
I created a minimalistic repository for reproduction.
https://github.com/byteCrunsher/temp-reproduction
The development directory contains the static fileserver, the base Vue app that should render the vue apps and the apps themselves. Please keep in mind that the first app is a Vue app and the second app is just a basic HTML file.
The production directory contains the fileserver, the distributed Vue apps and the html file. Simply run the static fileserver from the production directory and go to http://localhost:3000
you should see my current work then.
Update
When I use the vue directive v-html
and store the response into a data attribute ( https://hatebin.com/casjdcehrj ) then I get this response from the server
and this is the content I get when I use await response.text();
I just solved the problem by my own. I took the IFrame / object tags way
document.getElementById(
"customAppContainer"
).innerHTML = `<object style="width: 100%; height:100%;" data="http://localhost:3000/subApps/${appKey}"></object>`;
This way has the drawback to isolate the embedded app from the main app. But it's possible to communicate via localStorage. The subApp extends its router.js file with
router.afterEach((to, from) => {
localStorage.subAppRouteUpdate = to.path;
});
This event will trigger whenever I navigate through that embedded app and will store the updated url to the localStorage. The base app can listen to that storage change. In the App.vue it adds an event listener and appends the subApp url to the browser url
<script>
export default {
created() {
window.addEventListener("storage", () => {
const fullRoute = this.$router.currentRoute.fullPath;
const routeSegments = fullRoute.split("/");
const appsIndex = routeSegments.indexOf("apps");
const newBaseUrlSegments = routeSegments.slice(0, appsIndex + 2);
const newBaseUrl = newBaseUrlSegments.join("/");
const subAppRoute = localStorage.subAppRouteUpdate;
const updatedUrl = newBaseUrl.concat(subAppRoute);
history.replaceState(null, null, updatedUrl);
});
}
};
</script>
With this approach I'm currently able to navigate through my containerized subApp and can still udpdate the browser url.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.