Vue (at least Vue 2) allows developers to register components globally:
import MyComponent from '@/components/MyComponent'
Vue.component('my-component-name', MyComponent)
Which then results into:
I read in another SO post that Svelte does not support global component registration. However, I would still like to achieve the same results as given above.
How would I approach this in Svelte?
I rolled my own when I needed a similar function (it was very handy when adding some interactive components to a WordPress site).
Here's the code I used:
/**
* Turn a svelte element into a simple web component
* The content inside the web component will be passed in as the `slot` attribute and it's of type: `Array<ChildNode>`
* @param svelteElem
* @param elemName
*/
export function elementify(svelteElem: any, elemName: string) {
class newElem extends HTMLElement {
svelteComp: any
constructor() {
super()
//at this point the internal elements are not mounted yet, so we need to do it before the next `paint` cycle
window.requestAnimationFrame(() => {
let children: Record<string, Array<ChildNode>> = { '___': [] }
Array.from(this.childNodes).forEach(elem => {
let slotName = "___"
if ((elem instanceof HTMLElement) && elem.getAttribute("slot")) slotName = elem.getAttribute("slot")
if (!children[slotName]) children[slotName] = []
children[slotName].push(elem)
elem.remove()
})
let props: Record<string, any> = {
slot: children,
parent: this,
}
let attribs:Array<string>
if (typeof(this.getAttributeNames)=="undefined"){
attribs = Array.from(this.attributes).map(x=>x.name)
} else {
attribs = this.getAttributeNames()
}
attribs.forEach(attr => {
props[attr] = this.getAttribute(attr)
})
let comp = this.svelteComp = new svelteElem({
target: this,
props
})
// transfer the properties and methods exposed by the component
Object.getOwnPropertyNames(Object.getPrototypeOf(comp)).forEach(prop => {
if (prop != "constructor") (this as any)[prop] = comp[prop]
})
})
}
// connectedCallback() {
// }
// disconnectedCallback(){
// }
}
customElements.define(elemName, newElem);
}
To use it, you simply do this:
import MyComponent from './components/MyComponent.svelte'
elementify(MyComponent,"my-component-name")
After that you can use the <my-component-name> tag and the Svelte component will be mounted inside that component.
My solution might have some flaws but it's been working for months in production.