Question: Equivalent to domElementGetter in single-spa-react?
anarchist912 opened this issue · comments
Hello! First of all, what you are developing here is great!
We are currently testing whether we can build the next generation of our software on single-spa. We have Vue and React developers. So we'd like to integrate a Vue app into our main React app.
But as there a multiple microfrontends, we don't want to have to add a new mount point element for each, but instead solve it programmatically, like this is possible with single-spa-react:
I saw this in the https://gitlab.com/TheMcMurder/single-spa-portal-example and it works like a charm!
const reactLifecycles = singleSpaReact({
React,
ReactDOM,
rootComponent,
domElementGetter
})
function domElementGetter() {
const id = "demo-vue"
let el = document.getElementById(id)
if (!el) {
el = document.createElement('div')
el.id = id
document.getElementById("sspa-mount").appendChild(el)
}
return el
}
Is it possible with single-spa-vue? I tried some things, but did not get any results.. if I just mount on an existing DOM node, the Vue app is rendered properly.
Where should I hook in?
const vueLifecycles = singleSpaVue({
Vue,
appOptions: {
render: h => h(() => SystemJS.import(`@module/demo3/app.js`)),
},
})
export const bootstrap = vueLifecycles.bootstrap
export const mount = vueLifecycles.mount
export const unmount = vueLifecycles.unmount
Hi @anarchist912, yes it is possible to specify which dom element a single-spa-vue application goes into.
These docs hint at how to do it, but I think they could be more explicit. Here's an example of how:
const vueLifecycles = singleSpaVue({
Vue,
appOptions: {
el: '#my-special-container',
render: h => h(() => SystemJS.import(`@module/demo3/app.js`)),
}
})
I have created single-spa/single-spa.js.org#147 to clarify this in the documentation.
I'm closing this issue because this is something single-spa-vue already supports. Feel free to comment further or reopen.
Hello Joel! Thanks for the quick reply!!
Sorry, I should have put my question more cleary. I know that it's possible to specify the id of the target dom element... The Docs were clear enough for me. 👍
But is it possible to create the element on the fly, if it does not exist yet?
Something like this? single-spa-react allows it..
let el = document.getElementById('renderTarget')
if (!el) {
el = document.createElement('div')
el.id = 'renderTarget'
document.body.appendChild(el)
}
Thank you very much in advance!
Ah I see now. single-spa-vue already creates the dom element and appends it to document.body, but you want to append it to a sspa-mount
container instead.
You could do that with the following code:
const vueLifecycles = singleSpaVue({
Vue,
appOptions: {
el: '#sspa-mount #app1',
render: h => h(() => SystemJS.import(`@module/demo3/app.js`)),
}
})
export const bootstrap = [
() => {
document
.getElementById('sspa-mount')
.appendChild(Object.assign(
document.createElement('div'),
{id: 'app1'}
))
},
lifecycles.bootstrap
]
export const mount = lifecycles.mount
export const unmount = lifecycles.unmount
Exporting an array of lifecycle functions will call them in order, so by the time that single-spa-vue tries to mount the application the dom element will have already been created.
Great! I just had to wrap that first function in the array into a promise, like so:
export const bootstrap = [
() => new Promise((resolve, reject) => {
document
.getElementById('sspa-mount')
.appendChild(Object.assign(
document.createElement('div'),
{id: 'app1'}
))
resolve()
})
},
lifecycles.bootstrap
]
Thanks again.
Ah yes - has to return a promise. Glad that is working for you