DEV Community

Kevin Jump
Kevin Jump

Posted on • Updated on

Early Adopter's guide to Umbraco v14 - Package structure.

If like me you have been keeping a keen eye on Umbraco things you will know that Umbraco v14 is next, and it is the version where the backoffice is being completely replaced.

out goes the familiar if a little clunky (and unsupported) AngularJs back end and in comed the all new shiny-trendy-froody WebComponents, Typescript, Lit, platform.

Personally i know this is going to be a steep learning curve, and i've started to look at how we are going to migrate our packages such as uSync and Translation Manager to this brave new world.

Initially i did some open-it-up-and-just-start-migrating work, and that has given me some insights, I will probibly start again, with a few tweaks to make things easier on myself.

Now this post, isn't about my journey its about setting up the project structures so you can build an Umbraco package and get it all working for yourself.

this is early adoptor advice based on Umbraco14-preview008 - its likely to change when new releases come out

Also, I am planning to make this into a .net template which sort of means you won't have to type all of this just to get yourself a package ready project.

Update!

There is a now a dotnet new template that will build a project just like this for you. See our blog post on the template for more info.

Project Structure

Now personally i like to setup my solutions so i have a project for the package and a test website so i can see what is going on.

+ -- MyPackageProject.sln
  + -- <package>.csproj
  + -- <package>.Client.csproj
  + -- <package>.Core.csproj
  + -- MyPackage.Site.csproj
Enter fullscreen mode Exit fullscreen mode

<package>.client.csproj

This is the backoffice front end project, it will have all the typescript,javascript, vite stuff in it.

this project will be a razor class library, and will compile down so the assets are in a wwwroot/app_plugins/package folder which is the thing Umbraco will absorb.

<package>.core.csproj

the core package has all the backend code/controllers/api endpoints in it, this is the bit of code that runs on the server does the work within the CMS, anything backendy.

For more complex packages i am considering seperating out any management api controllers from this package, then i can share core logic between v13 and v14 sites and only have the v14 controllers in a seperate project. but this is only a theory right now!

<package>.csproj

this is the nuget package, usually really simple, it contains references to the .assets and core packages, so when its built this is the thing people will install.

Step 1: Creating the solution.

This bit is probibly the simplest, you can create a new blank solution in visual studio,

Add three new Class Library projects - once core, assets and package class. these are the packages.

or you can do it via the command line (hint: this can be made scriptable)

dotnet new classlib -n MyPackage
dotnet new classlib -n MyPackage.Core
dotnet new classlib -n MyPackage.Client
Enter fullscreen mode Exit fullscreen mode

Create an umbraco site.

Again if you have the templates installed you can do this in visual studio.

there is a guide to install the latest preview releases on the Umbraco documentation site.

For the console junkie the cli commands are:

dotnet new install Umbraco.Templates::14.0.0--preview004
dotnet new umbraco -n MyPackage.Website 
Enter fullscreen mode Exit fullscreen mode

Add everything to the solution.

Again in visual studio, this will have happened as you added the projects.

dotnet sln add (ls -r **/*.csproj)
Enter fullscreen mode Exit fullscreen mode

ClassLib to RazorLib.

Now you can create razorclasslibraries directly, but you end up deleting lots of files. If you create classlibraries you can make them razor class libraries by chaning a line in the .csproj file.

in the .client project. change :

<Project Sdk="Microsoft.NET.Sdk.">
Enter fullscreen mode Exit fullscreen mode

to

<Project Sdk="Microsoft.NET.Sdk.Razor">
Enter fullscreen mode Exit fullscreen mode

and add a <StaticWebAssetBasePath> value to the property group element.

<StaticWebAssetBasePath>/</StaticWebAssetBasePath>
Enter fullscreen mode Exit fullscreen mode

This tells Asp.Net that anything in the wwwroot folder will be presented in the website at the root level. meaning if we put our files in app_plugins/package then they will be accessible at https://site/app_plugins/package

you package.client.csproj file should look like this.

<Project Sdk="Microsoft.NET.Sdk.Razor">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <StaticWebAssetBasePath>/</StaticWebAssetBasePath>
  </PropertyGroup>
</Project>
Enter fullscreen mode Exit fullscreen mode

Dependencies.

Inorder to the packages to relate to each other when they build, we need to make certain projects have dependencies on others.

the package.csproj project needs to have a dependency on the .client and .core projects - so when we build the nuget package will also have these dependencies.

dotnet add .\MyPackage\ reference .\MyPackage.Core\
dotnet add .\MyPackage\ reference .\MyPackage.Client\
Enter fullscreen mode Exit fullscreen mode

Also we should make it so our website has a dependency on the package, so we can test it.

dotnet add .\MyPackage\ reference .\MyPackage.Website\
Enter fullscreen mode Exit fullscreen mode

Now if that has all worked, (either in visual studio or in the command line) your solution should look something like this.

Project structure in visual studio

hint : ii ./mypackageproject.sln will open the solution in visual studio from the command line.

2. Vite and all that

Now you have the basic structure down, you are almost there, any code you right in the .core project will end up in the website and any files in the wwwroot folder of the .assets project will end up visible to Umbraco.

one minor flaw you have no files in the wwwroot folder (hey you probibly don't even have a wwwroot folder).

this is because we haven't added any of the new front end magic yet.

Here we are going to be doing close to what the umbraco docs tell us to do but with some tweaks.

cd ./mypackage.assets 
npm create vite@latest assets -- --template lit-ts
Enter fullscreen mode Exit fullscreen mode

this will create the vite package in a sub folder of your assets project. but it will currently use lit 3.x and Umbraco is running on lit 2.8.0. so you need to change that in the package.json file.

cd assets
npm install
npm install --force --registry https://www.myget.org/F/umbracoprereleases/npm/ -D @umbraco-cms/backoffice@14.0.0--preview004
Enter fullscreen mode Exit fullscreen mode

vite.config.ts

My vite.config.ts file is slightly diffrent from umbraco's

import { defineConfig } from "vite";

export default defineConfig({
    build: {
        lib: {
            entry: "src/index.ts", // your web component source file
            formats: ["es"],
        },
        outDir: "../wwwroot/app_plugins/mypackage", 
        emptyOutDir: true,
        sourcemap: true,
        rollupOptions: {
            external: [/^@umbraco/],
            onwarn: () => { },
        },
    },
});
Enter fullscreen mode Exit fullscreen mode

this is diffrent from the config in umbraco docs because it puts the out put into the wwwroot folder, so our built files become part of the razor class library.

and this point we also clean up the vite template, we don't need the .svg and .css files. and we can remove myelement.ts, we are going to replace it with a index.ts
as the entry point for our projects.

umbraco-package.json

Now we need an umbraco-package.json file in our project so in our assets/public folder we create this one.

{
    "$schema": "../umbraco-package-schema.json",
    "name": "mypackage",
    "id": "mypackage",
    "version": "0.1.0",
    "allowTelemetry": true,
    "extensions": [
        {
            "name": "mypackage.entrypoint",
            "alias": "mypackage.EntryPoint",
            "type": "entryPoint",
            "js": "/app_plugins/mypackage/assets.js"
        }
    ]
}
Enter fullscreen mode Exit fullscreen mode

Here we are going to have an 'entrypoint' extension which will point to a js file that does all the work.

we will then be defining all of our other extensions in typescript. In my opinion this is cleaner, gives you better intellisense, etc and just means you never have to worry about the umbraco-package.json file again.

Now you will notice here the schema file will give you a warning because we don't have that yet.
for the purposes of our build we can get it by building the webiste.

dotnet build .\MyPackage.Website\

this will give us an umbraco-package-schema.json which we can copy to the root of our assets folder. in the MyPackage.Client project.

Entry point

As above we are going to have a typescript file do all the work of registering our extensions.

so in the src folder we are creating index.ts

import { UmbEntryPointOnInit } from '@umbraco-cms/backoffice/extension-api';

// load up the things here. 

export const onInit: UmbEntryPointOnInit = (_host, extensionRegistry) => {

    // register them here. 
    // extensionRegistry.registerMany(...)
};
Enter fullscreen mode Exit fullscreen mode

A Basic skeleton of a package

This is the basic skeleton, of a package layout, from here you can add extensions to the src folder -

when built things will arrive in your wwwroot/app_plugins folder.

and because its all razor the website will get them and refresh.


last tip now, consider adding a "watch" command to your package.json file

vite build --watch
Enter fullscreen mode Exit fullscreen mode

With this in place when you change a .ts file in your assets/src folder, vite will rebuild the files, razor will detect the changes, and the umbraco back office will reload in your browser all without you having type/press anything else.

Top comments (0)