mount Vue apps into container of main Vue app
I finally got it working with the following approach and maybe this will help someone. Suggestions highly appreciated!
Base App:
The base app which renderes all the sub-apps has a CustomAppContainer view that loads the sub-apps into a div container.
<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>
Further I added mode: 'history'
to the router.
export default new Router({
mode: 'history',
routes: [
{
path: '/',
component: Home
},
{
path: '/apps/*',
component: CustomAppContainer,
}
]
})
I put the build files of that app into my production directory in a folder called base
File Server:
I created a static Express file server that always serves the index.html file of the base app. But I can request the index.html file of the sub-app too.
const express = require('express');
const path = require('path');
const fs = require('fs');
const cors = require('cors');
const app = express();
const router = express.Router();
app.use(cors());
app.use(express.static(path.resolve(__dirname, '../base')));
fs.readdirSync(path.resolve(__dirname, '../apps')).forEach(appName => {
app.use(express.static(path.resolve(__dirname, `../apps/${appName}`)));
});
router.get('/subApps/:appName', function(req, res) {
res.sendFile(path.resolve(__dirname, `../apps/${req.params.appName}/index.html`));
});
router.get('*', function(req, res) {
res.sendFile(path.resolve(__dirname, '../base/index.html'));
});
app.use('/', router);
app.listen(3000, function() {
console.log('Fileserver listening on port 3000');
});
Custom App:
When creating custom apps all I have to do is to extend the router config
export default new Router({
base: '/my-first-custom-app/',
mode: 'history',
routes: [
{
path: '/',
component: PageOne,
},
{
path: '/two',
component: PageTwo,
},
],
});
and rename the #app
ID to #customApp
in the index.html, main.js and App.vue.
Further I put the build files of that sub-app into my production directory in a folder called apps.
This allows me to create mulitple apps and render them into a div container of my main app container. The sub-app itself doesn't have to be a Vue app. I can create new apps with Jquery, Angular or React too, or even just a plain .html file.
1
Vue does not know
CustomAppContainer
Try to add import CustomAppContainer from "path/to/CustomAppContainer.vue"
It must be in .vue file.
2
Vue does not know
#customAppContainer
Yes, that selector must be in index.html
. Yours is in CustomAppContainer
.
Try to add to index.html
(usually in /public folder) something like <div id="#app"></div>
and replace .$mount('#customAppContainer');
with .$mount('#app');
3
Vue router needs <router-view>
tag. So, try this markup:
<!-- In template is all page -->
<template>
<!-- Some stuff as navigation... -->
<nav>
<!-- Router links - renders as "a" element -->
<router-link to="/one">To /one</router-link>
<!-- Or use standard tags - they're also good -->
<a href="/two">To /two</a>
</nav>
<!-- In this component would be component chosen in router (Home.vue) -->
<router-view/>
</template>
4
Router.js needs import:
import Home from "path/to/the/Home.vue"
export default new Router({
base: '/one/',
routes: [
{
path: '/',
component: Home,
},
],
});
All is good?