npm package: @linked-planet/loader-tools
Description: Tools for to loader apps and observe fields
Author: Markus Toepfer
Latest version: 0.9.0

# Loader-Tools Library

This library is to ease the replacement of fields in the Jira UI / Service Desk UI and also contains a loader to easily load custom app modules.

## Usage

### Installation and Setup

`npm i -D @linked-planet/loader-tools`

It is important that the final bundle also *includes all requirements* as Jira bundles everything in one huge `batch.js` and cannot load outside modules.

Either use the **AppLoader** to load an app directly, use the **Observer** tools to observe and handle field changes, or use `registerReplaceElementObserver` or `replaceElement` to replace HTMLElements in pages.


At first, a *plugin definition* is required, which follows the `PluginSettings` type:

```ts
export const pluginSettings: PluginSettings = {
    pluginName: "plugin-name",
    pluginGroupId: "com.linked-planet.plugin.jira"
}
```

The plugin settings and the app name are used by the App Loader to load the app, and by the Config tools to get the REST API URL, which can be retrieved using `Config.getRestApiBaseUrl(pluginSettings)`, and looks like:

```ts
const restApiBaseUrl = `${window.location.protocol}//${window.location.host}/rest/${pluginSettings.pluginName}/1.0`
```

### BatchJS and Jira Resources

The ultimate goal is to produce a Javascript Loader bundle which can be bundled by Jira. This means the Javascript bundle is copied by the plugin package process to `target/classes/js` and included from there in the *batch.js* of Jira.

This has certain requirements:

* must be a commonJS bundle
* is not allowed to have any exports

## Tools

Several categories of tools are available.

### Configs

The Config tools provide the option to fetch and cache configs from a set REST endpoint and provide that globally by using `getProjectConfig` with the help of the *plugin settings*, which are used to determine the correct endpoint address for the Jira plugin. The REST `baseURL` can also be obtained by `getRestApiBaseUrl`. In many cases we do not need a project config in the observer and app loading.

### App Loader

The app loader loads an application. The method for it is `initFrontendApp`, and it requires the plugin settings and the app name. It automatically determines which mode the app runs in (dev, dev-productionbundle, production).
Optionally, a starter function can be provided, which is used to start the app. This is only required if the app does not start when the bundle loading is complete.


### Observer

The observer tools are a simple library to ease the creation of MutationObservers on DOM elements, and to organize and handle callbacks used on mutation events of observed elements.

A simple use case could be:

```ts
Observer.registerObserverCallback("#content", () => console.log("content was modified"))
Observer.registerObserverCallback("#content", () => console.log("content was modified, callback 2"))
Observer.registerObserver("#content", {
    childList: true,
    subtree: false
})

```

This can be used in combination with the App Loader to replace Jira fields with custom apps.

#### Handling Of Fields

Jira recreates elements, which renders connected mutation observers useless and potentially leaks memory. A way around this is to use a mutation observer on a high-level element (i.e. `body`), which does not get recreated, and re-register the mutation observers using the corresponding selectors of the elements. The Observer library will automatically disconnect old mutation observers and create new ones if the underlying element has changed.

#### Replacing Fields

In most cases we want to replace a field rendered by Jira with a custom element. For this the `registerReplaceElementObserver` is a one stop solution.

```ts
registerReplaceElementObserver("#content", {
    target: () =>
        document.querySelector<HTMLElement>(selector),
	replacement:
        reactAppDiv, // The replacement element MUST have an ID
	cssBundleSelector:
		"link[rel='stylesheet'][data-lp-css-bundle='true']",
	shouldSkipReplacement: () => {
		return (
			ServiceDesk.isCurrentPageInServiceDeskPortal(
				serviceDeskPortalId
			) ?? false
		)
	},
	onReplacementComplete: () => {
		// add a bit more bottom margin to the help text
		const element =
			document.querySelector<HTMLElement>(selector)
		const divs = element.getElementsByTagName("div")
		for (const div of divs) {
			if (div.id.endsWith("-helper")) {
				div.style.marginBottom = "14px"
			}
		}
	}
})
```


### Fields

The Fields part includes helper utilities to handle fields.

### Utils

Utils currently only contain the frontend mode indicator handling, which displays a small hint on the bottom right corner of a page if the app is in *dev* or *dev-productionbundle* mode.

## Documentation Overview

<!-- doc-gen DOCS_OVERVIEW -->
**@linked-planet/loader-tools v0.9.0**

***

# @linked-planet/loader-tools v0.9.0

## Namespaces

- [AppLoader](#apploader-namespace)
- [Fields](#fields-namespace)
- [ServiceDesk](#servicedesk-namespace)

## Interfaces

- [InitFrontendAppOptions](#interface-initfrontendappoptions)
- [PluginSettings](#interface-pluginsettings)
- [ProjectConfig](#interface-projectconfig)

## Type Aliases

- [FrontendModeType](#type-alias-frontendmodetype)
- [ObserverCallback](#type-alias-observercallback)
- [ReplaceElementObserverOptions](#type-alias-replaceelementobserveroptions)

## Variables

- [Config](#variable-config)
- [FrontendMode](#variable-frontendmode)
- [Observer](#variable-observer)
- [Utils](#variable-utils)

## Functions

- [getLoggerPrefix](#function-getloggerprefix)
- [initFrontendApp](#function-initfrontendapp)
<!-- end-doc-gen -->

<!-- doc-gen DOCS_CONTENT -->

## API Documentation

## AppLoader Namespace

### @linked-planet / namespaces / AppLoader / type-aliases / InitFrontendAppOptions

[**@linked-planet/loader-tools v0.9.0**](#)

***

[@linked-planet/loader-tools](#) / [AppLoader](#) / InitFrontendAppOptions

# Type Alias: InitFrontendAppOptions

> **InitFrontendAppOptions** = [`InitFrontendAppOptions`](#interface-initfrontendappoptions)

Defined in: [loader/index.ts:11](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/loader/index.ts#L11)

---

### @linked-planet / namespaces / AppLoader / variables / initFrontendApp

[**@linked-planet/loader-tools v0.9.0**](#)

***

[@linked-planet/loader-tools](#) / [AppLoader](#) / initFrontendApp

# Variable: initFrontendApp()

> `const` **initFrontendApp**: (`options`) => `void` = `_initFrontendApp`

Defined in: [loader/index.ts:10](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/loader/index.ts#L10)

Initializes and loads a frontend application module with automatic mode detection and DOM readiness handling.

This is the main entry point for loading frontend applications. It:
- Automatically detects the appropriate loading mode based on hostname (localhost = development, others = production)
- Handles DOM readiness states (waits for DOMContentLoaded if needed)
- Sets up Shadow DOM if requested
- Manages fallback loading strategies (dev → dev-productionbundle → production)

## Parameters

### options

[`InitFrontendAppOptions`](#interface-initfrontendappoptions)

Configuration object for frontend app initialization

## Returns

`void`

## Throws

Error if appName is not provided

## Throws

Error if pluginSettings are not provided

## Throws

Error if no valid app root element can be found

## Example

```ts
'''typescript
initFrontendApp({
  appName: "my-react-app",
  pluginSettings: { pluginName: "my-plugin", pluginGroupId: "com.example" },
  developmentPort: 3000,
  appRootElementSelector: "#app-container",
  useShadowRoot: true,
  starterFunc: (rootElement) => {
    console.log("App loaded in:", rootElement);
  }
});
'''
```

---

## Fields Namespace

### @linked-planet / namespaces / Fields / type-aliases / ReplaceElementObserverOptions

[**@linked-planet/loader-tools v0.9.0**](#)

***

[@linked-planet/loader-tools](#) / [Fields](#) / ReplaceElementObserverOptions

# Type Alias: ReplaceElementObserverOptions

> **ReplaceElementObserverOptions** = [`ReplaceElementObserverOptions`](#type-alias-replaceelementobserveroptions)

Defined in: [fields/index.ts:20](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/fields/index.ts#L20)

---

### @linked-planet / namespaces / Fields / variables / getCustomFieldIDByLabel

[**@linked-planet/loader-tools v0.9.0**](#)

***

[@linked-planet/loader-tools](#) / [Fields](#) / getCustomFieldIDByLabel

# Variable: getCustomFieldIDByLabel()

> `const` **getCustomFieldIDByLabel**: (`labelText`) => `string` \| `null` = `_getCustomFieldIDByLabel`

Defined in: [fields/index.ts:15](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/fields/index.ts#L15)

Get a custom field's ID by its visible label text, automatically handling optional field suffixes.
Supports both <label for="…"> and wrapping label patterns.

If a matching form control element doesn't have an ID, one will be generated and assigned.

## Parameters

### labelText

`string`

The text content of the label to search for (automatically checks with and without "(optional)" suffix)

## Returns

`string` \| `null`

The ID of the associated input/select/textarea element, or null if not found

## Example

```typescript
// Finds labels with text "Priority" or "Priority (optional)"
const fieldId = getCustomFieldIDByLabel("Priority");
if (fieldId) {
  const field = document.getElementById(fieldId);
}
```

---

### @linked-planet / namespaces / Fields / variables / registerReplaceElementObserver

[**@linked-planet/loader-tools v0.9.0**](#)

***

[@linked-planet/loader-tools](#) / [Fields](#) / registerReplaceElementObserver

# Variable: registerReplaceElementObserver()

> `const` **registerReplaceElementObserver**: (`observingElementSelector`, `options`) => `void` = `_registerReplaceElementObserver`

Defined in: [fields/index.ts:16](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/fields/index.ts#L16)

Registers a DOM observer that monitors for changes and triggers element replacement when conditions are met.

This function sets up a MutationObserver that watches for DOM changes on the specified element
and automatically calls replaceElement when changes occur. It handles both immediate execution
(if DOM is ready) and deferred execution (waiting for DOMContentLoaded).

## Parameters

### observingElementSelector

`string`

CSS selector for the element to observe for DOM changes

### options

[`ReplaceElementObserverOptions`](#type-alias-replaceelementobserveroptions)

Configuration object for element replacement (same as replaceElement options)

## Returns

`void`

---

### @linked-planet / namespaces / Fields / variables / replaceElement

[**@linked-planet/loader-tools v0.9.0**](#)

***

[@linked-planet/loader-tools](#) / [Fields](#) / replaceElement

# Variable: replaceElement()

> `const` **replaceElement**: (`options`) => `void` = `_replaceElement`

Defined in: [fields/index.ts:18](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/fields/index.ts#L18)

Replaces an element in the DOM with a replacement element and manages CSS bundle state.

This function handles the common pattern of:
1. Finding a target element in the DOM
2. Checking if a replacement element is already present (by checking if the replacement element has an id)
3. Managing CSS bundle enabling/disabling based on element presence
4. Optionally executing additional operations after the replacement

The original element is hidden rather than removed, and the replacement is inserted before it.

## Parameters

### options

[`ReplaceElementObserverOptions`](#type-alias-replaceelementobserveroptions)

Configuration object for element replacement

## Returns

`void`

## Example

```typescript
const reactApp = document.createElement("div");
reactApp.id = "my-react-app";

replaceElement({
  target: () => document.querySelector(".original-field"),
  shouldSkipReplacement: () => {
    return document.querySelector(".original-field") === null;
  },
  replacement: reactApp,
  cssBundleSelector: "link[data-plugin-name='my-plugin-name'][data-app-name='my-app-name']",
  onReplacementComplete: () => {
    console.log("Replacement completed");
  }
});
```

---

### @linked-planet / namespaces / Fields / variables / replaceInputWithSpan

[**@linked-planet/loader-tools v0.9.0**](#)

***

[@linked-planet/loader-tools](#) / [Fields](#) / replaceInputWithSpan

# Variable: replaceInputWithSpan()

> `const` **replaceInputWithSpan**: (`id`, `replacementId`) => `boolean` = `_replaceInputWithSpan`

Defined in: [fields/index.ts:13](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/fields/index.ts#L13)

Replaces form input elements within a field group with read-only span elements containing their current values.
Also hides any buttons within the field group.

## Parameters

### id

The ID of a custom field element within the target field group (null values are handled gracefully)

`string` | `null`

### replacementId

`string`

The ID to assign to the replacement span elements

## Returns

`boolean`

True if the field group was found and processed successfully, false otherwise

## Example

```ts
'''typescript
const success = replaceInputWithSpan("custom-field-123", "readonly-display-123");
if (success) {
  console.log("Field successfully converted to read-only");
}
'''
```

---

### @linked-planet / namespaces / Fields / variables / setInputToDate

[**@linked-planet/loader-tools v0.9.0**](#)

***

[@linked-planet/loader-tools](#) / [Fields](#) / setInputToDate

# Variable: setInputToDate()

> `const` **setInputToDate**: (`fieldSelector`, `date`, `dateFormat`) => `void` = `_setInputToDate`

Defined in: [fields/index.ts:14](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/fields/index.ts#L14)

Sets the value of an input element to a formatted date string.

## Parameters

### fieldSelector

`string`

CSS selector for the input element to update

### date

`Date`

The Date object to format and set as the input value

### dateFormat

`string`

The format string pattern (supports DD, MM, YYYY tokens, e.g., "DD.MM.YYYY")

## Returns

`void`

## Example

```typescript
setInputToDate("#my-date-field", new Date(), "DD.MM.YYYY");
```

---

## ServiceDesk Namespace

### @linked-planet / namespaces / ServiceDesk / variables / isCurrentPageInServiceDeskPortal

[**@linked-planet/loader-tools v0.9.0**](#)

***

[@linked-planet/loader-tools](#) / [ServiceDesk](#) / isCurrentPageInServiceDeskPortal

# Variable: isCurrentPageInServiceDeskPortal()

> `const` **isCurrentPageInServiceDeskPortal**: (`serviceDeskPortalId`) => `boolean` = `_isCurrentPageInServiceDeskPortal`

Defined in: [servicedesk/index.ts:4](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/servicedesk/index.ts#L4)

Validates if the Service Desk portal ID in the current URL matches the expected portal ID.

Extracts the portal ID from the URL path and compares it with the provided Service Desk portal ID.
The portal ID is expected to be the 5th segment in the URL path (index 4).

## Parameters

### serviceDeskPortalId

`number`

The expected Service Desk portal ID to validate against

## Returns

`boolean`

True if portal IDs match or if portal ID not found in URL, false if they don't match

## Example

```typescript
// URL: /servicedesk/customer/portal/123/...
const result = isCurrentPageInServiceDeskPortal(123); // returns true
const result2 = isCurrentPageInServiceDeskPortal(456); // returns false
```

---

## Interfaces

### interfaces / InitFrontendAppOptions

[**@linked-planet/loader-tools v0.9.0**](#)

***

[@linked-planet/loader-tools](#) / InitFrontendAppOptions

# Interface: InitFrontendAppOptions

Defined in: [loader/app-loader.ts:9](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/loader/app-loader.ts#L9)

Configuration options for initializing a frontend application module.

## Properties

### appName

> **appName**: `string` \| (`mode`) => `string`

Defined in: [loader/app-loader.ts:13](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/loader/app-loader.ts#L13)

The name identifier of the frontend module to load.

***

### appRootElement?

> `optional` **appRootElement**: `HTMLElement` \| `ShadowRoot` \| `null`

Defined in: [loader/app-loader.ts:23](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/loader/app-loader.ts#L23)

The shadow root to use for the app. If not provided, the app will be loaded into the document head.

***

### appRootElementSelector?

> `optional` **appRootElementSelector**: `string`

Defined in: [loader/app-loader.ts:21](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/loader/app-loader.ts#L21)

The element ID containing the app, if not provided, the app will be loaded into the document head, else it is loaded as shadow DOM attached to this element.

***

### cssBundleFile?

> `optional` **cssBundleFile**: `string`

Defined in: [loader/app-loader.ts:33](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/loader/app-loader.ts#L33)

The file name of the css bundle to load.

#### Default

`${pluginSettings.pluginName}.css`

#### Example

```typescript
cssBundleFile: "my-plugin.css"
```

***

### developmentPort

> **developmentPort**: `number`

Defined in: [loader/app-loader.ts:19](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/loader/app-loader.ts#L19)

The port to use for the development server.

***

### mode?

> `optional` **mode**: [`FrontendModeType`](#type-alias-frontendmodetype)

Defined in: [loader/app-loader.ts:17](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/loader/app-loader.ts#L17)

The mode to load the module in.

***

### pluginSettings

> **pluginSettings**: [`PluginSettings`](#pluginsettings)

Defined in: [loader/app-loader.ts:11](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/loader/app-loader.ts#L11)

The settings of the plugin.

***

### starterFunc()?

> `optional` **starterFunc**: (`appRootElement?`) => `void`

Defined in: [loader/app-loader.ts:15](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/loader/app-loader.ts#L15)

The function to call once the module's script has loaded successfully.

#### Parameters

##### appRootElement?

`HTMLElement` | `ShadowRoot`

#### Returns

`void`

***

### useShadowRoot?

> `optional` **useShadowRoot**: `boolean`

Defined in: [loader/app-loader.ts:25](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/loader/app-loader.ts#L25)

Whether to use a shadow root for the app.

---

### interfaces / PluginSettings

[**@linked-planet/loader-tools v0.9.0**](#)

***

[@linked-planet/loader-tools](#) / PluginSettings

# Interface: PluginSettings

Defined in: [configs/project-config.ts:6](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/configs/project-config.ts#L6)

Configuration interface for plugin settings containing Maven artifact information.

## Properties

### pluginGroupId

> **pluginGroupId**: `string`

Defined in: [configs/project-config.ts:10](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/configs/project-config.ts#L10)

The Maven group ID of the plugin providing the module.

***

### pluginName

> **pluginName**: `string`

Defined in: [configs/project-config.ts:8](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/configs/project-config.ts#L8)

The Maven artifact ID (plugin name) of the plugin.

---

### interfaces / ProjectConfig

[**@linked-planet/loader-tools v0.9.0**](#)

***

[@linked-planet/loader-tools](#) / ProjectConfig

# Interface: ProjectConfig

Defined in: [configs/project-config.ts:18](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/configs/project-config.ts#L18)

Base interface for project configuration. Extend this interface to add project-specific settings.

## Properties

### serviceDeskPortalId?

> `optional` **serviceDeskPortalId**: `number`

Defined in: [configs/project-config.ts:19](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/configs/project-config.ts#L19)

---

## Type Aliases

### type-aliases / FrontendModeType

[**@linked-planet/loader-tools v0.9.0**](#)

***

[@linked-planet/loader-tools](#) / FrontendModeType

# Type Alias: FrontendModeType

> **FrontendModeType** = `"production"` \| `"development"` \| `"dev-productionbundle"`

Defined in: [utils/frontend-mode.ts:17](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/utils/frontend-mode.ts#L17)

---

### type-aliases / ObserverCallback

[**@linked-planet/loader-tools v0.9.0**](#)

***

[@linked-planet/loader-tools](#) / ObserverCallback

# Type Alias: ObserverCallback()

> **ObserverCallback** = (`mutations?`) => `void`

Defined in: [observer/observer.ts:8](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/observer/observer.ts#L8)

Callback type for MutationObserver events.

## Parameters

### mutations?

`MutationRecord`[]

Optional array of mutation records that occurred

## Returns

`void`

---

### type-aliases / ReplaceElementObserverOptions

[**@linked-planet/loader-tools v0.9.0**](#)

***

[@linked-planet/loader-tools](#) / ReplaceElementObserverOptions

# Type Alias: ReplaceElementObserverOptions

> **ReplaceElementObserverOptions** = `object`

Defined in: [fields/replace-element.ts:104](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/fields/replace-element.ts#L104)

Configuration options for element replacement operations.

## Example

```typescript

const replacement = document.createElement("div");
replacement.id = "my-react-app";

const options: ReplaceElementObserverOptions = {
  target: () => document.querySelector("#my-field"),
  replacement,
  cssBundleSelector: "link[data-my-css='true']",
  shouldSkipReplacement: () => false,
  onReplacementComplete: () => console.log("Done")
};
```

## Properties

### cssBundleSelector?

> `optional` **cssBundleSelector**: `string`

Defined in: [fields/replace-element.ts:109](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/fields/replace-element.ts#L109)

Optional CSS selector for the CSS bundle link element to enable/disable

***

### onReplacementComplete()?

> `optional` **onReplacementComplete**: () => `void`

Defined in: [fields/replace-element.ts:110](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/fields/replace-element.ts#L110)

Optional callback function to execute additional operations during replacement

#### Returns

`void`

***

### replacement

> **replacement**: `HTMLElement` & `object` \| () => `HTMLElement` & `object`

Defined in: [fields/replace-element.ts:106](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/fields/replace-element.ts#L106)

The HTML element that will replace the target element, requires an Id

***

### shouldSkipReplacement()?

> `optional` **shouldSkipReplacement**: () => `boolean`

Defined in: [fields/replace-element.ts:111](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/fields/replace-element.ts#L111)

Optional function to check if replacement should proceed; if returns true, replacement is skipped

#### Returns

`boolean`

***

### target

> **target**: `string` \| () => `HTMLElement` \| `null`

Defined in: [fields/replace-element.ts:105](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/fields/replace-element.ts#L105)

Function that returns the target HTML element to be replaced, or a CSS selector string

---

## Variables

### variables / Config

[**@linked-planet/loader-tools v0.9.0**](#)

***

[@linked-planet/loader-tools](#) / Config

# Variable: Config

> `const` **Config**: `object`

Defined in: [configs/project-config.ts:92](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/configs/project-config.ts#L92)

## Type Declaration

### getProjectConfig()

> **getProjectConfig**: \<`T`\>(`projectConfigUrl`, `pluginSettings`) => `Promise`\<`T`\>

Fetches and caches the project configuration from the REST API.

The configuration is cached globally after the first successful fetch.
Subsequent calls return the cached configuration without making additional requests.

#### Type Parameters

##### T

`T` *extends* [`ProjectConfig`](#interface-projectconfig)

#### Parameters

##### projectConfigUrl

`string`

The URL path to fetch config from (absolute, relative to REST base, or sub-path)

##### pluginSettings

[`PluginSettings`](#interface-pluginsettings)

Plugin configuration for constructing the full REST API URL

#### Returns

`Promise`\<`T`\>

Promise resolving to the project configuration

#### Throws

Error if projectConfigUrl is empty or if the fetch request fails

#### Example

```ts
'''typescript
const config = await getProjectConfig<MyProjectConfig>(
  "/project/PROJ",
  { pluginName: "my-plugin", pluginGroupId: "com.example" }
);
'''
```

### getRestApiBaseUrl()

> **getRestApiBaseUrl**: (`pluginSettings`) => `string`

Constructs the REST API base URL using plugin settings and current window location.

#### Parameters

##### pluginSettings

[`PluginSettings`](#interface-pluginsettings)

Plugin configuration containing Maven artifact information

#### Returns

`string`

The base URL for REST API calls (e.g., "https://example.com/rest/my-plugin/1.0")

#### Throws

Error if pluginSettings is not provided

---

### variables / FrontendMode

[**@linked-planet/loader-tools v0.9.0**](#)

***

[@linked-planet/loader-tools](#) / FrontendMode

# Variable: FrontendMode

> `const` **FrontendMode**: `object`

Defined in: [utils/frontend-mode.ts:80](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/utils/frontend-mode.ts#L80)

Utility namespace for managing frontend development modes.

## Type Declaration

### getFrontendMode()

> **getFrontendMode**: () => [`FrontendModeType`](#type-alias-frontendmodetype)

Retrieves the current frontend development mode.

#### Returns

[`FrontendModeType`](#type-alias-frontendmodetype)

The currently active frontend mode

### setFrontendMode()

> **setFrontendMode**: (`devMode`) => `void`

Sets the frontend development mode and displays a visual indicator.

Updates the global frontend mode and shows a non-intrusive indicator in the bottom-right
corner for non-production modes. The indicator appears after a 500ms delay to prevent flickering.

#### Parameters

##### devMode

[`FrontendModeType`](#type-alias-frontendmodetype)

The frontend mode to set (production, development, or dev-productionbundle)

#### Returns

`void`

---

### variables / Observer

[**@linked-planet/loader-tools v0.9.0**](#)

***

[@linked-planet/loader-tools](#) / Observer

# Variable: Observer

> `const` **Observer**: `object`

Defined in: [observer/observer.ts:164](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/observer/observer.ts#L164)

## Type Declaration

### hasObserver()

> **hasObserver**: (`selector`) => `boolean`

Checks whether an observer is currently registered for the given selector.

#### Parameters

##### selector

`string`

CSS selector to check

#### Returns

`boolean`

True if an observer exists for this selector, false otherwise

### registerObserver()

> **registerObserver**: (`selector`, `observerOptions`) => `null` \| `undefined`

Creates and registers a MutationObserver for the specified element.

Note: If you need to change observer options, unregister the existing observer first.

#### Parameters

##### selector

`string`

CSS selector for the target element (only the first matching element is observed)

##### observerOptions

`MutationObserverInit`

MutationObserver configuration options

#### Returns

`null` \| `undefined`

The created MutationObserver instance, or null if element not found or observer already exists

#### See

[https://developer.mozilla.org/en-US/docs/Web/API/MutationObserverInit](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserverInit) for observerOptions details

### registerObserverCallback()

> **registerObserverCallback**: (`selector`, `cb`) => `void`

Registers a callback function to be executed when DOM mutations occur on the specified element.

#### Parameters

##### selector

`string`

CSS selector for the target element to observe

##### cb

[`ObserverCallback`](#type-alias-observercallback)

Callback function to execute when mutations are detected

#### Returns

`void`

### unregisterObserver()

> **unregisterObserver**: (`selector`, `removeCallbacks`) => `void`

Disconnects and removes an observer for the specified element.

#### Parameters

##### selector

`string`

CSS selector for the target element

##### removeCallbacks

`boolean` = `true`

Whether to also remove all registered callbacks for this selector (default: true)

#### Returns

`void`

### unregisterObserverCallback()

> **unregisterObserverCallback**: (`selector`, `cb`) => `void`

Removes a previously registered callback from the observer system.

#### Parameters

##### selector

`string`

CSS selector for the target element

##### cb

[`ObserverCallback`](#type-alias-observercallback)

The specific callback function to unregister

#### Returns

`void`

---

### variables / Utils

[**@linked-planet/loader-tools v0.9.0**](#)

***

[@linked-planet/loader-tools](#) / Utils

# Variable: Utils

> `const` **Utils**: `object`

Defined in: [utils/index.ts:6](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/utils/index.ts#L6)

## Type Declaration

### fetchFromPlugin()

> **fetchFromPlugin**: \<`T`\>(`url`, `pluginSettings`, `options?`) => `Promise`\<`T`\>

Fetches data from a plugin's REST API endpoint with automatic URL construction and error handling.

Automatically constructs the full REST API URL using the plugin settings and handles
JSON response parsing and HTTP error checking.

#### Type Parameters

##### T

`T`

#### Parameters

##### url

`string`

The REST API endpoint path (can be absolute, relative to REST base, or sub-path)

##### pluginSettings

[`PluginSettings`](#interface-pluginsettings)

Plugin configuration containing Maven artifact information for URL construction

##### options?

`RequestInit`

Optional fetch request configuration (headers, method, body, etc.)

#### Returns

`Promise`\<`T`\>

Promise resolving to the parsed JSON response of type T

#### Throws

Error if the HTTP response is not ok (status >= 400)

#### Example

```typescript
interface UserData { id: number; name: string; }

const userData = await fetchFromPlugin<UserData>(
  "/users/123",
  { pluginName: "my-plugin", pluginGroupId: "com.example" },
  { method: "GET" }
);
```

### getLoggerPrefix()

> **getLoggerPrefix**: () => `string`

Get the logger suffix [LOADER-TOOLS-<suffix>].

#### Returns

`string`

The logger suffix.

### setLoggerSuffix()

> **setLoggerSuffix**: (`suffix`) => `void`

Set the logger suffix (adds this as postfix to [LOADER-TOOLS]).

#### Parameters

##### suffix

`string`

The suffix to set (adds this as postfix to [LOADER-TOOLS]).

#### Returns

`void`

---

## Functions

### functions / getLoggerPrefix

[**@linked-planet/loader-tools v0.9.0**](#)

***

[@linked-planet/loader-tools](#) / getLoggerPrefix

# Function: getLoggerPrefix()

> **getLoggerPrefix**(): `string`

Defined in: [utils/logger-prefix.ts:15](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/utils/logger-prefix.ts#L15)

Get the logger suffix [LOADER-TOOLS-<suffix>].

## Returns

`string`

The logger suffix.

---

### functions / initFrontendApp

[**@linked-planet/loader-tools v0.9.0**](#)

***

[@linked-planet/loader-tools](#) / initFrontendApp

# Function: initFrontendApp()

> **initFrontendApp**(`options`): `void`

Defined in: [loader/app-loader.ts:436](https://github.com/linked-planet/frontend-loader-tools/blob/7793d89b3aa142d0eb6c9030f9591ddb835b179e/src/loader/app-loader.ts#L436)

Initializes and loads a frontend application module with automatic mode detection and DOM readiness handling.

This is the main entry point for loading frontend applications. It:
- Automatically detects the appropriate loading mode based on hostname (localhost = development, others = production)
- Handles DOM readiness states (waits for DOMContentLoaded if needed)
- Sets up Shadow DOM if requested
- Manages fallback loading strategies (dev → dev-productionbundle → production)

## Parameters

### options

[`InitFrontendAppOptions`](#interface-initfrontendappoptions)

Configuration object for frontend app initialization

## Returns

`void`

## Throws

Error if appName is not provided

## Throws

Error if pluginSettings are not provided

## Throws

Error if no valid app root element can be found

## Example

```ts
'''typescript
initFrontendApp({
  appName: "my-react-app",
  pluginSettings: { pluginName: "my-plugin", pluginGroupId: "com.example" },
  developmentPort: 3000,
  appRootElementSelector: "#app-container",
  useShadowRoot: true,
  starterFunc: (rootElement) => {
    console.log("App loaded in:", rootElement);
  }
});
'''
```

---


<!-- end-doc-gen -->