Release Notes / Version 12.2506.0
Table Of ContentsWhile the Workflow App has been replaced by a new implementation based on React instead of ExtJs, the API for custom workflows has largely been kept unchanged.
There are notable breaking changes:
Localization based on resource bundles
The well-known Studio mechanism for localization based on resource
bundles was (and in the Content App still is) based on ExtJs
mechanisms. So to localize your custom workflow labels and texts, you
need to apply a new mechanism. You still have resource bundles as
before in different languages. However, you need to register the
localized bundles for “de” and “ja” using the
registerLocale() function:
import { registerLocale } from "@coremedia/studio-client.i18n-models";
registerLocale(Gcc_properties, "de", async () => {
await import("./Gcc_de_properties");
});
Following that, when localizing a specific resource bundle key, you
need to use the getLocalizer() function:
import { getLocalizer} from "@coremedia/studio-client.i18n-models";
const localize = await getLocalizer(Gcc_properties);
TextField({
label: localize("TranslationGlobalLink_submission_status_key"),
...
}),
WorkflowPlugin API
The type WorkflowPlugin is no longer generic, this
is now only the case for its properties
startWorkflowFormExtension and
runningWorkflowFormExtension. In addition, for the
two form extension, the factory function
StartWorkflowFormExtension<ViewModel>() and
RunningWorkflowFormExtension<ViewModel>()
have been introduced respectively. So the registration of a new
workflow plugin follows this pattern:
interface GccViewModel {
...
}
const getGccWorkflowPlugin = async (): Promise<TranslationWorkflowPlugin> => {
workflowType: "TRANSLATION",
workflowName: "TranslationGlobalLink",
...
startWorkflowFormExtension: StartWorkflowFormExtension<GccViewModel>({ ... }),
runningWorkflowFormExtension: RunningWorkflowFormExtension<GccViewModel>({ ... }),
...
}
getGccWorkflowPlugin().then((gccWorkflowPlugin) => {
workflowPlugins._.addTranslationWorkflowPlugin(gccWorkflowPlugin);
});
For more details, please have a look at the “Custom Workflow” Section of the Studio Developer Manual.
ResourceBundleUtil
The utility class ResourceBundleUtil from “@jangaroo/runtime/l10n/ResourceBundleUtil” has been deprecated in jangaroo.npm and is not supported inside the workflow app. In order to replace “ResourceBundleUtil.override” please just utilize Web API “Object.assign” instead which doesn’t require any import. You can also remove the dependency “@jangaroo/runtime” from your package if it was only utilized for that.
To retain code completion and type errors if a overridden resource bundle key does not longer exist in the default resource bundle, you can utilize “satisfies Partial<MyResourceBundle_properties>” (supported by jangaroo.npm 3.3.1+), e.g.
import ResourceBundleUtil from "@jangaroo/runtime/l10n/ResourceBundleUtil";
import MyResourceBundle_properties from "./MyResourceBundle_properties";
ResourceBundleUtil.override(MyResourceBundle_properties, {
someKey: "...",
});
should be replaced by:
import MyResourceBundle_properties from "./MyResourceBundle_properties";
Object.assign(MyResourceBundle_properties, {
someKey: "...",
} satisfies Partial<MyResourceBundle_properties>);
Public API
Whenever utilizing studio-client API you now need to make sure to only utilize Public API. In addition to this Public API needs to be imported from the package export, meaning that deep path imports inside the package will not work. The new plugin build will report corresponding warnings and errors.
Example:
import contentTypeLocalizationRegistry from "@coremedia/studio-client.cap-base-models/content/contentTypeLocalizationRegistry";
now needs to be:
import { contentTypeLocalizationRegistry } from "@coremedia/studio-client.cap-base-models";
The identifiers are always named after the module file name of the old import.
If you have split your plugin into multiple packages this applies to all packages used inside the runtime code of the plugin. Please also be aware that in case you have used packages that did not contain any Public API at all, the plugin build may not report any warnings or errors. Those packages will be handled as custom third party packages, so their code is just bundled into your plugin. This could lead to unintended side effects if you rely on shared runtime state or similar in that case.
Extensions Mechanism
While the API is mostly the same there are changes regarding affecting the extension package structure because the new Workflow App is no longer running with ExtJS and though cannot work with the ExtJS based “Dynamic Packages” mechanism.
This has been replaced with a new mechanism based on https://webpack.js.org/concepts/module-federation/.
package.json changes
In order to switch an extension for the old workflow app to the new workflow app, you need to make notable changes to the devDependencies and the scripts of the package.json:
Declare package type as “module” by adding:
"type": "module",
Remove “@jangaroo/core” and “@jangaroo/build” and make sure you have at least these devDependencies
"devDependencies": {
"@babel/core": "^7.23.2",
"@coremedia/eslint-config-studio-client": "2506.0.0",
"@coremedia/studio-client.build-config": "2506.0.0",
"@coremedia/studio-client.workflow.shared-modules": "2506.0.0",
"eslint": "^8.57.0",
"rimraf": "^5.0.7",
"typescript": "^5.8.2",
"webpack": "^5.98.0",
"webpack-cli": "^6.0.1"
}
Make sure to have at least these scripts:
"scripts": {
"clean": "rimraf ./dist",
"prebuild": "sync-tsconfig-project-references src --includeDevDependencies",
"build": "tsc --project src && webpack build --mode=production",
"watch": "webpack watch --mode=development",
"lint": "eslint \"src/**/*.ts*\""
}
Add a new section “coremedia” with the following entry (replacing the $placeholder with a name containing only letters or underscore [a-z_]+):
"coremedia": {
"projectExtensionFor": "studio-client.workflow",
"plugins": {
"$placeholder": "./dist/appEntry.js"
}
},
Other files
Remove jangaroo.config.js
Create .eslintrc.cjs
module.exports = {
extends: ["@coremedia/eslint-config-studio-client"],
};
Create babel.config.js
import { babelConfig } from "@coremedia/studio-client.build-config";
export default babelConfig;
Create webpack.config.js
import { sharedModules } from "@coremedia/studio-client.workflow.shared-modules";
import { getPluginWebpackConfig } from "@coremedia/studio-client.build-config";
export default getPluginWebpackConfig({
name: "$placeholder",
sharedModules: {
"@coremedia/studio-client.workflow.shared-modules": sharedModules,
},
});
Where $placeholder must be the same identifier that you have used in your package.json.
Create src/index.ts
// empty, must be there for webpack...
Create src/tsconfig.json (the new prebuild script will automatically modify this tsconfig.json later):
{
"extends": "@coremedia/studio-client.build-config/tsconfig-shared.json",
"compilerOptions": {
"rootDir": ".",
"outDir": "../dist/src"
}
}
Create src/plugin.ts
export const initPlugin = async () => {
// add your plugin code here, e.g. start utilizing the custom workflow api
};
Now you have a base skeleton for the new plugin mechnism. You can start adding your own code to the src/plugin.ts
Migrating Content Type Localization for Content App and Workflow App
You usually want to have Content Type Localization only once in a shared packages. If you have sticked to the examples for Content Type Localization provided in the blueprint there is a migration path for the new plugin mechanism. While all examples in the blueprint are adjusted, the general approach looks as follows.
Add the initialization codee to the src/plugin.ts of your plugin
export const initPlugin = async () => {
const module = await import("@coremedia-blueprint/studio-client.my-doctypes");
await module.initMyDocTypes();
};
For the shared package itself (in the example this is “@coremedia-blueprint/studio-client.my-doctypes”) you now need to create and export the corresponding init method. This can be as simple as just exporting it in their index.ts:
import { contentTypeLocalizationRegistry } from "@coremedia/studio-client.cap-base-models";
import MyDocTypes_properties from "./MyDocTypes_properties";
export const initMyDocTypes = async () => {
registerLocale(MyDocTypes_properties, "de", async () => {
await import("./BlueprintDoctypesDocTypes_de_properties");
});
registerLocale(MyDocTypes_properties, "ja", async () => {
await import("./BlueprintDoctypesDocTypes_de_properties");
});
const localizer = await getLocalizer(MyDocTypes_properties);
contentTypeLocalizationRegistry.addLocalization("CMMyDocType", {
displayName: localize("Content_displayName"),
})
// ...
};
For more a more complex examples (including different locales), check the packages @coremedia-blueprint/studio-client.workflow.blueprint-doctypes-plugin and @coremedia-blueprint/studio-client.blueprint-doctypes in the blueprint workspace.
Customization via ExtJS plugins
The ExtJS Plugin mechanism was never supported in the old Workflow App. However, it was possible to ignore that and just utilize the API in order to make customizations. As we switched to React, there is no replacement for that and though we cannot offer a migration path here.
Customization for the Workflow App can now only be done via the provided CustomWorkflowApi and additional APIs like the contentLocalizationRegistry.
(CMS-24826)


