I'm currently rendering Vue apps inside object tags (iframe could work too) of a container/master Vue app. First I setup a fileserver serving that container or the requested sub-app to render inside the div.
For the sake of simplicity I will only show the required routing of my Node/Express server
// serve the sub-app on demand
router.get('/subApps/:appName', function(req, res) {
res.sendFile(path.resolve(__dirname, `../apps/${req.params.appName}/index.html`);
});
// always render the app container if no sub-app was requested
router.get('*', function(req, res) {
res.sendFile(path.resolve(__dirname, '../base/index.html'));
});
My app container / master Vue app is inside the view file rendered on /apps/:appName, requests that sub-app and wraps it into object tags
document.getElementById("customAppContainer").innerHTML = `<object style="width: 100%; height:100%;" data="http://localhost:3000/subApps/${appKey}"></object>`;
This approach works fine but the rendered sub-app uses the startup url http://localhost:3000/subApps/app-one although it should use the url http://localhost:3000/apps/app-one. When the sub-app loads the router instance I have to change the startup url from the iframe url to the browser url (parent).
I thought about fixing that with history.replaceState
const router = new Router({ ... });
router.afterEach((to, from) => {
localStorage.subAppRouteUpdate = to.path;
});
if (window.location !== window.parent.location) {
const browserUrl = top.location.href;
history.replaceState(null, null, browserUrl);
}
export default router;
Why do I want to do this? The App.vue of the master app should append the sub-app route to the browser url. With this approach it's possible to update the browser url while navigating inside the sub-app. I achieve this by storing the sub-app url to the local storage and listen for local storage changes at the master app side. So the App.vue file uses this code
<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>
to enable a routing while using IFrames. It almost works, this is what I get
Unfortunately it happens that when calling / of the sub-app the browser url gets updated to
although I'm expecting
Reproduction:
I created a repository for reproduction / testing. Does someone know what might be wrong or how to fix that url updating?
Update:
I think the error occurs because in the router.js of the subApp I'm firing this code
if (window.location !== window.parent.location) {
const browserUrl = top.location.href;
history.replaceState(null, null, browserUrl);
}
router.afterEach((to, from) => {
console.log({ urlToAppend: to.path });
localStorage.subAppRouteUpdate = to.path;
});
The replaceState function will update the IFrame url from /subApps/app-one to the correct browser url /apps/app-one. Unfortunately this will trigger the afterEach event and to.path results in /apps/app-one although it should be /.
If the url would be /apps/app-one/users/create the after each event should trigger with /users/create of course.
But I didn't figured out how to fix this first triggered event.
