Components
Every component a module registers joins the application's global components and resolves by name anywhere: in templates and in the page trees the backend sends.
To resolve a registered component in code, import resolveDmsComponent explicitly from #dms/frontend-module:
import { resolveDmsComponent } from "#dms/frontend-module";
const Banner = resolveDmsComponent("AcmeBanner");
Component prefix
To keep the components of two modules from colliding, a module declares a componentPrefix. It goes in front of the name of every component the module registers:
const frontendModule: DmsFrontendModule = {
componentPrefix: "Acme",
setup(sdk) {
sdk.registerComponent("Banner", Banner); // registered as AcmeBanner
},
};
The full name, prefix included, is the one a template uses (<AcmeBanner>) and the one a backend sends (CustomComponent("AcmeBanner"), or acme-banner). Names are compared ignoring case, a leading lazy and non-alphanumeric characters. A leading Dms is not dropped: it is the DMS module's own prefix.
Collisions and replacements
When two modules register the same name, the module of higher priority keeps it, and a warning names both. A module that means to replace another module's component registers the full name without its own prefix, which is not reported:
sdk.registerComponent("AcmeBanner", MyBanner, { prefix: false });
Private code
A module's app/build/ directory is never auto-imported. Its components are registered so that backend pages can name them, but they are the module's internals, not a surface other modules should build on. See Auto-imports.
Page loading state
After a client navigation, the page renders under a <Suspense> until its chunk and any async setup resolve. useDmsPageLoading(), auto-imported, is true meanwhile, so a layout can show its own placeholder instead of an empty page body:
<script setup lang="ts">
const pageLoading = useDmsPageLoading();
</script>
<template>
<slot />
<PageSkeleton v-if="pageLoading" />
</template>
It stays false on the server and during hydration, which render the resolved page, for a page that does not suspend, and once a pending page is left.
Components rendered inside an svg
Modules usually register their components lazily, with defineAsyncComponent, and the page renders under a <Suspense>. Vue mounts an async component that resolves under a <Suspense> with the <Suspense>'s element namespace rather than the namespace of the place it renders in. A component resolved by name whose root is an SVG element (<path>, <g>…) is then created as an HTML element inside the <svg>, and the browser draws nothing (vuejs/core#15639).
Import such components directly instead, for example the node and edge types passed to Vue Flow:
import { markRaw } from "vue";
import RelationEdge from "./RelationEdge.vue";
const edgeTypes = markRaw({ relation: RelationEdge });