Umbraco-package.json vs UmbExtensionManifest

Hi all,

I’m currently looking into how to do custom dashboards etc.. on the new backoffice, and I’m a tad confused about the difference between registering stuff with a umbraco-package.json vs a UmbExtensionManifest.

I’ve created a custom dashboard following the docs, using an umbraco-package.json, and it all works great; but I’ve just tried out Lottie’s Opinionated Package Starter (LottePitcher/opinionated-package-starter: Get a head start when creating Umbraco Packages) and that uses a UmbExtensionManifest file to register it’s dashboard.

So my question is, in what use cases would I use one over the over?

In the end, it doesn’t really matter HOW extensions are registered. The starting point is the umbraco-package.json and you can perfectly register all extensions there. You can imagine though that it might get pretty big if you have a lot of extensions. In my case, I usually register only two things in the umbraco-package.json: the language files and a bundle that contains all my extensions. Within that bundle, I use the extension manifest to register the various extensions in various locations and in various files to keep it organized. The Umbraco (15) dotnet template for extensions does the same thing and so does the Opinionated package starter.

Ok I think I need some example to make it more clear.
I have a bundle manifest file that looks like this:

//bundle.manifest.ts
import { manifests as entrypoints } from './entrypoints/manifest';
import { manifests as dashboards } from './dashboards/manifest';
import { manifests as propertyeditors } from './propertyeditors/manifest';
import { manifests as workspaces } from './workspaces/manifest';

// Job of the bundle is to collate all the manifests from different parts of the extension and load other manifests
// We load this bundle from umbraco-package.json
export const manifests: Array<UmbExtensionManifest> = [
    ...entrypoints,
    ...dashboards,
    ...propertyeditors,
    ...workspaces
];

This is the starting point for my vite application that will be used to generate a bundle. Each of these individual manifest that are references here look like this for example:

// Registers the workspace, which is the settings workspace for content expiration
export const manifests: Array<UmbExtensionManifest> = [
{
    type: 'workspaceView',
    name: 'example workspace view',
    alias: 'proudnerds.example.workspace.app',
    weight: 101, //The 'info' tab has a weight of 100, the 'content' tab 200
    element: () => import('./example-workspace-view'),
    meta: {
        label: 'Example',
        pathname: 'example',
        icon: 'icon-chip',
    },
    conditions: [
        {
            "alias": "Umb.Condition.WorkspaceAlias",
            "match": "Umb.Workspace.Document"
        }
    ]
}];

So using the extension manifest, I can register extensions in various placed to keep everything organized. Once Vite had generated a bundle, I can just use that bundle in my umbrac-package.json:

{
	"$schema": "../../umbraco-package-schema.json",
	"id": "ProudNerds.Umbraco.AI",
	"name": "Umbraco AI",
	"version": "GetsGenerated",
	"extensions": [
		{
			"name": "Example",
			"alias": "ProudNerds.Example",
			"type": "bundle",
			"js": "/App_Plugins/ProudNerds.Example/example.js"
		}
	]
}

This keeps the umbraco-package.json clean. Also, it helps that the extensions are build into the bundle, so there is compile time checking if something is wrong with it.

3 Likes

Awesome, cheers Luuk, that clears things up a lot :smiley:

I was looking at the umbraco-package.json file in the same way as I used to use the package.manifest file in the old backoffice , where I had a seperate package.manifest for each extension (dashboard, content app etc…) in my App_Plugins; so to me it felt a bit redundant having both a umbraco-package.json and a UmbExtensionManifest per extension in App_Plugins.. but looking at it from the way you’ve described, where you have only one umbraco-package.json, that references each plugin’s UmbExtensionManifest, makes total sense to me now!