ホームページ
2026年2月6日

(第2回)Auto dictionaries:Umbraco 13 から 17 への冒険 — プロジェクト構造と TypeScript への移行準備

Umbraco
パッケージ
TypeScript
C#

今、Umbraco 13 はセキュリティアップデートだけを受けられるので、アップデートする時間だ!

次の「LTS」バージョンは Umbraco 17。僕は「LTS」バージョンだけをアップデートしたいので、僕の Umbraco パッケージ Auto dictionaries を Umbraco 17 にアップデートする。

第1回はここでもっと読めるが、この記事だけでも内容は理解できる。

先に、「Visual Studio 2026」にアップデートして、Webプロジェクトを Umbraco 17にアップデートした。

今回はプロジェクトの構造を変えて、フロントエンドのコードを「AngularJS」から「TypeScript」に変える。

僕はたいていバックエンドのコードで働いているので、バックエンドのコードのほうがいい。

だから、今回はバックエンドのコードを直し始めたいけど、ほかのプロジェクトを働いた時、

多くのバックエンドのコードが使えなかった。

そのため、フロントエンドのコードを「AngularJS」から「TypeScript」に変え始めたほうがいい。


予定

今、僕の予定は

  1. 「Visual Studio 2026」にアップデートする
  2. Webのプロジェクトは Umbraco 17にアップデートする
  3. プロジェクトの構造を変える
  4. フロントエンドのコードは「AngularJS」から「TypeScript」に変える
  5. バックエンドのコードを直す
  6. ユニットテストのコードを直す


3. プロジェクトの構造を変える

これからは「TypeScript」を使うため、「TypeScript」のソースコードとコンパイル後のコードは同じフォルダに置かない。

コンパイル後のコードはwwwrootに出力するので、「TypeScript」のコードは別のフォルダが必要だ。

このブログでケビン・ジャンップを見つけた。

Early Adopter's guide to Umbraco v14 - Package structure

このブログ記事によると、ケビンはこのパッケージの構造を使っている。

+ -- <package>.sln
  + -- <package>.csproj
  + -- <package>.Client.csproj
  + -- <package>.Core.csproj
  + -- <package>.Site.csproj

このパッケージの構造を見始めた。その構造はとてもよさそうだから、僕も使いたい。でも、よく見た時、ちょっと問題を見つけた。

ケビンはフロントエンドのコードのために、自分の「NuGet」のパッケージがある。

それはほしくない。だから、ほかの方法を使う。

「Auto dictionaries」のプロジェクトの中で、「Client」のフォルダを作ったと、その中で、フロントエンドのコードを置く。

たいてい僕はCMDでフロントエンドのコードをビルドすると、Visual Studioでバックエンドのコードをビルドする。それはとても大変だった。

でも!ケビンの他のブログは「An Umbraco v14 Early Adopter's Development setup」を見つけた!

そのブログ記事に、ケビンはてんさいな解決策を書いた!

ケビンの解決策は全部でVisual Studioができる!

「Task Runner Explorer」といえ、Visual Studioの拡張機能はフロントエンドコードコンパイルを使える。

その拡張機能を使いたい時、プロジェクトのルートでがpackage.jsonある。

だから、ネスト構造を使わない。

でも、ルートの中で、package.json を作った。

そして、これで書いた

{
  "name": "auto-dictionaries",
  "private": true,
  "version": "17.0.0",
  "scripts": {
    "install-client": "cd ./AutoDictionaries/Client/ && npm install",
    "build-watch": "cd ./AutoDictionaries/Client/ && npm run watch"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

このファイルの一番大切はcd ./AutoDictionaries/Client/

これから、Visual Studioでビルド&ウォッチのコードができる。

この解決策はとても気に入っている!

3ステップは終わった!次に、一番難しい問題を解決しようと思う。


4. フロントエンドのコードは「AngularJS」から「TypeScript」に変える

まず「Vite」をインストールする

npm create vite@latest

「TypeScript」と「Lit」を選ぶ。

それは既定構造を受けたと、そのパスはAutoDictionaries/Client

今、2つの方ができる。

AutoDictionaries/Client/public/umbraco-package.jsonにはすべて登録するか、「backofficeEntryPoint」だけ登録すると、AutoDictionaries/Client/src/index.tsには他のを登録。たくさんことを登録するから、AutoDictionaries/Client/public/umbraco-package.jsonの解決策を使った特、そのファイルは長くすぎると思うから、index.tsの解決策を使おうと思ういる。

import type { UmbEntryPointOnInit } from '@umbraco-cms/backoffice/extension-api';
import { manifests } from './manifests.js';

export * from './components/index.js';

export const onInit: UmbEntryPointOnInit = (_host, extensionRegistry) => {
	extensionRegistry.registerMany(manifests);
};

APIのリクエストをしたいなら、「Bearer token」を追加しないと。「UMB_AUTH_CONTEXT 」を使える。

型付きAPIを受けたいから、「Hey API」のnpmのパッケージを使う。

「Hey API」を使うために、Swaggerを実装したほうがいい。

だから、早いSwaggerの実装をする。

namespace AutoDictionaries.Composers
{
	internal class ConfigureSwaggerGenOptions : IConfigureOptions<SwaggerGenOptions>
	{
		public void Configure(SwaggerGenOptions options)
		{
			options.SwaggerDoc(
			  "autoDictionaries",
			  new OpenApiInfo
			  {
				  Title = "Auto Dictionaries Management Api",
				  Version = "Latest"
			  });
			options.CustomOperationIds(e => $"{e.ActionDescriptor.RouteValues["action"]}");
		}
	}
}

とテスト用のコントローラー を作る

namespace AutoDictionaries.Controllers
{
	[ApiController]
	[ApiVersion("1.0")]
    [MapToApi("autoDictionaries")]
	[ApiExplorerSettings(GroupName = "autoDictionaries")]
	[Authorize(Policy = AuthorizationPolicies.BackOfficeAccess)]
	public class AutoDictionariesApiController : Controller
    {
                [HttpGet("get-all-views")]
                public string GetAllViews()  => string.Empty;
    }
}

次に、openapi-ts.config.tsを作る。

import { defineConfig } from '@hey-api/openapi-ts';
export default defineConfig({
	input: 'https://localhost:44360/umbraco/swagger/autoDictionaries/swagger.json',
	output: {
		path: 'src/api',
	},
	plugins: [
		{
			name: '@hey-api/sdk',
			asClass: true,
			classNameBuilder: '{{name}}Service',
		},
	],
});

自己署名証明書の問題があるから、「cross-env」のnpmのパッケージをインストールする

今は、プロジェクトを起動してからこのコマンドを実行し、型付きAPIを作る。

cross-env NODE_TLS_REJECT_UNAUTHORIZED=0 openapi-ts

index.ts「Bearer token」を追加する

export const onInit: UmbEntryPointOnInit = (_host, extensionRegistry) => {
	extensionRegistry.registerMany(manifests);
	host.consumeContext(UMBAUTH_CONTEXT, (_auth) => {
		if (!_auth) return;
		var config = _auth.getOpenApiConfiguration();
		client.setConfig({
			auth: config.token,
			baseUrl: config.base,
			credentials: config.credentials,
		});
		client.interceptors.request.use(async (request, _options) => {
			const token = await _auth.getLatestToken();
			request.headers.set('Authorization', `Bearer ${token}`);
			return request;
		});
	});
};

今、APIのリクエストができる!

では、今は、新しいツリーを作った。これは正直かなり大変だった。多くの時間がかかったので、あとで自分の記事として書こうと思っている。

後で、いろんなことを変えた。

たとえば、先に、IDを使ったけど、今は、GUIDを使った。

先は、これはディクショナリのアイテムのパス。

/umbraco#/translation/dictionary/edit/11

でも今は、これになった。

/umbraco/section/translation/workspace/dictionary/edit/62cbe7af-2ff1-4584-b2e2-6f50cf11e116

それに、Umbracoでは「Infinite Editor」の名前を変えた。今の名前は「Sidebar」だ。

先は、「Infinite Editor」を使った。

vm.generateDictionaries.editor = {
   view: "/App_Plugins/AutoDictionaries/backoffice/infiniteEditors/generateDictionaries.html",
    title: "Generate dictionaries",
    size: "medium",
    selectedContent: vm.selectedContent,
   autoDictionariesModel: vm.view,
   allowTranslate: vm.allowTranslate,
    submit: function () {
      editorService.close();
      $route.reload();
    },
   close: function () {
       editorService.close();
    }
};

editorService.open(vm.generateDictionaries.editor)


でも今は、先ずは「UmbModalToken」を使った。

import { UmbModalToken } from "@umbraco-cms/backoffice/modal";
import { PreviewAddNewDictionaryItemToViewDto } from "../api";
export const GENERATE_DICTIONARY_MODAL_TOKEN = new UmbModalToken<PreviewAddNewDictionaryItemToViewDto, string[]>('autoDictionaries.generateDictionaries.modal', {
    modal: {
        type: 'sidebar',
        size: 'medium'
    }
});

そしてコンストラクタで 「Context API」 を使って、コンテキストを消費する

constructor() {
	super();

	this.consumeContext(UMB_MODAL_MANAGER_CONTEXT, (_instance) => {
		this._modalContext = _instance;
	});
}

最終に、これで開ける。

async #openCreateDictionaryModal() {
  const modalContext = await this._modalContext?.open(this, GENERATE_DICTIONARY_MODAL_TOKEN, {
      data: {
         staticContent: this._selectedContent,
         autoDictionariesModel: this._item,
         canTranslate: this._translationSetting
      } as PreviewAddNewDictionaryItemToViewDto
    });

  await modalContext?.onSubmit();
}

それは、比較的目立つ変更だと思う。

このステップはよくUmbraco 17のドキュメントで解決策と正しく使う「UUI Component」をさがしていたと。

でも、今までに、あまりドキュメントがないために、よく他のUmbraco 17のパッケージやブログやUmbraco 17のソースコードなどを見た。

それは一番大切だと思う。

4ステップはもうやっと終わった!


思ったこと

このステップはやっと終わった!

今回はたくさんことをした。新しいプロジェクトの構造がある。

「Task Runner Explorer」を使えた、嬉しくなった!

あまり「TypeScript」も使わなかったと。そのために、これはめちゃ難しかったと思う。

ケビン・ジャンップのブログは本当に大きな助け!

もうすぐパッケージをリリースできる!

最終はバックエンドのコードを直す!


リンク


パーツたち

  1. (第1回)Auto dictionaries:Umbraco 13 から 17 への冒険
  2. (第2回)プロジェクト構造と TypeScript への移行準備
  3. (第3回)もうすぐ。。。
ヨハネス・ランツ

ヨハネス・ランツ

ウェブ開発者・経験8年

採用可能

お問い合わせ