Skip to content

Frequently Asked Questions

How do I pass backend configuration to the frontend?

Section titled “How do I pass backend configuration to the frontend?”

Often, iTwin Studio Apps require the backend to provide initialization or configuration data to the frontend. StudioHost has a method to set configuration data on the backend, while StudioApp has a method to retrieve this data on the frontend.

Setting Data On Backend

In the backend, StudioHost provides a method called finalizeFrontendInitData(), which accepts a JSON object as input. This method stores the initialization data for the frontend to fetch when needed. It’s advisable to call this method in the backend as early as possible, within activateBackend(). Below is an example of how to use it:

export function activateBackend() {
StudioHost.finalizeFrontendInitData({
USE_DEBUGGER: process.env.USE_DEBUGGER,
DEV_MODE: process.env.DEV_MODE,
});
}

Getting Data On Frontend

On the frontend, StudioApp offers a method called getFrontendInitData(), which retrieves the data set by finalizeFrontendInitData() on the backend. Since this method relies on data already being set in the backend, it’s important to ensure that finalizeFrontendInitData() has been called before using getFrontendInitData(). Below is an example of how to use this method in frontend code:

export function activateFrontend() {
const initDataResult = await StudioApp.getFrontendInitData();
}

If getFrontendInitData() fails to retrieve data within a specified time (default is 5000ms), it may time out with an error. Users can increase the timeout by providing an optional options parameter to the method, as shown below:

StudioApp.getFrontendInitData({ timeoutInMS: 7000 });

How do I make sure my development environment is up-to-date?

Section titled “How do I make sure my development environment is up-to-date?”

@bentley/studio-cli has a studio-cli apps runtime-check command. On a Windows machine, navigate to your package directory and run the following to keep your debug environment up-to-date (run without the --fix flag to see the changes first):

npx --registry="https://pkgs.dev.azure.com/bentleycs/_packaging/Packages/npm/registry/" @bentley/studio-cli@latest apps runtime-check --fix

iTwin Studio’s build tools support .scss, .module.scss, .css, and .module.css files. Import the file and it will be automatically bundled for you.

import "styles.css";
import "styles.scss";
import styles from "styles.module.css";
import styles from "styles.module.scss";

In iTwin Studio, each app can have its own user preferences that users can modify using the User Preferences Editor. All user modified user preferences are stored in a userPreferences.json (or userPreferences.qa.json) file. On Windows, the path is %APPDATA%\Bentley\iTwin Studio\userPreferences.json. To integrate your app’s user preferences into the User Preferences Editor, follow these steps:

Step 1: Define the User Preferences Schema

Section titled “Step 1: Define the User Preferences Schema”

The first step is to create a JSON Schema file that defines the structure of your app’s preferences. This file should be added to the backend of your application and copied into your dist at build-time (see how to copy assets here). In the schema file, specify the preferences’ names, data types, and default values.

myapp.schema.json
{
$schema: "http://json-schema.org/draft-07/schema",
$id: "MyAppsSettings",
type: "object",
groupName: "myAppName",
properties: {
"myAppName/openSelectionOnStartup": {
title: "Always start iModel Selection page",
description: "MyApp:openSelectionOnStartup.description", // localized key
type: "boolean",
default: true,
},
"myAppName/maxRecents": {
title: "Max Recents",
type: "number",
default: 5,
description: "MyApp:maxRecents.description", // localized key
},
},
}

You can learn more about JSON Schema at JSON Schema Website.

In your backend code, you’ll need to import the StudioHost singleton from the @bentley/studio-apps-backend-api library. Initialize the schema by calling StudioHost.addUserPreferencesSchemaFile('path/to/schema/json'), where you provide the path to the JSON file you defined in Step 1. This step allows the User Preferences Editor in iTwin Studio to recognize your app’s preferences, and users can modify the values through the interface.

import { StudioHost } from "@bentley/studio-apps-backend-api";
const schemaPath = StudioHost.resolveAssetPath("backend/assets/settings.schema.json");
await StudioHost.addUserPreferencesSchemaFile(schemaPath);

As a developer, you can access the app’s settings on both the backend and the frontend:

Backend Access:

Developers can access the preferences on the backend using the StudioHost.getUserPreference method. This method enables you to retrieve the values of your app’s preferences and use them as needed in your backend logic.

Frontend Access:

On the frontend, developers can access the app’s preferences using the StudioApp.getUserPreference() method. This way, you can utilize these preferences in the app’s user interface and functionality on the frontend side.

For more comprehensive details and examples on how preferences are different from settings utilized in iTwin.js applications, you can refer to the iTwin.js Documentation.

There are two ways how svgs can be used in apps:

Like in any other application, you can use ES6 import syntax:

import icon from "./{relative path to svg}"

Currently supported formats include SVG, PNG and JPG images.

  • Build fails due to missing loader
No loader is configured for ...

Ensure that a loader is configured for your image. This can be done by adding a declaration.d.ts file in your frontend directory. Below is an example for SVG files:

declare module '*.svg' {
const content: string;
export default content;
}

Separate module declaration is need for every image type (png/jpg/svg) that is used in your project.

  • SVG is missing it’s <styles> tag after compiling.

There are known issues with loading more complex SVGs that rely on the styles tag. We recommend using the second approach for loading them, or getting in touch with our team to discuss this further.

In addition to using ES6 imports, assets can be loaded directly. This is mainly used to allow iTwin Studio to find images belonging to a specific app (to display them in the sidebar, etc.), but can be used within an app as well.

  1. Copy your assets folder to the dist folder. In your dev/build scripts, use the --copy arg to specify the folder location.
--copy frontend/assets
  1. Assets can be accessed via StudioApp.resolveAssetPath
StudioApp.resolveAssetPath("fronted/assets/icon.svg");

Note that the path should be relative to the root folder.

To use it as an image, we recommend using an img tag to resolve the image source.

<img src=${StudioApp.resolveAssetPath("fronted/assets/icon.svg")}/>

Posting telemetry (Azure Application Insights) in apps

Section titled “Posting telemetry (Azure Application Insights) in apps”

iTwin Studio exposes telemetry methods from its APIs. In order to post telemetry to Azure Application Insights , apps need to first initialize the telemetry service by calling StudioHost.initializeTelemetry(instrumentalKey) in the activateBackend method. After initializing, we can post the telemetry by calling StudioHost.postTelemetry({ ...telemetryData }) in the backend and StudioApp.postTelemetry({ ...telemetryData }) in the frontend.

Follow these steps to use studio-cli and upload your sourcemaps to Sentry using the sentry-cli option.

  • Ensure you are logged in to Sentry CLI or have set the necessary credentials. For more details, refer to the Sentry CLI documentation.
  1. Build your app with the --externalSourcemap flag enabled:

    Terminal window
    studio-cli apps build --externalSourcemap
  2. Inject Sentry Debug IDs into the build code and sourcemaps:

    Terminal window
    sentry-cli sourcemaps inject dist
  3. Package your app:

    Terminal window
    studio-cli apps package

    By default, .map files are excluded from the zip. Use the --dev flag if you want to include them.

  4. Upload sourcemaps to Sentry:

    Terminal window
    sentry-cli sourcemaps upload

You should now be able to see readable stack traces in your Sentry errors.

Use StudioApp.getApiOverrides() from @bentley/studio-apps-frontend-api to determine which development environment you are in. The API will return a serverEnvironmentPrefix of “dev”, “qa”, or "".

import { StudioApp } from "@bentley/studio-apps-frontend-api";
const environment = StudioApp.getApiOverrides();

Switching environments between PROD and QA

Section titled “Switching environments between PROD and QA”

See Switching Environment

How can I build a modular iTwin Studio app to prepare for dynamically loaded apps?

Section titled “How can I build a modular iTwin Studio app to prepare for dynamically loaded apps?”

Currently, iTwin Studio apps are designed to be monolithic. In the future, apps will be able to be composed of smaller units that can be delivered separately and optionally download and installed by users via an app store. In order to prepare for this, and for good practice in general, it is advised to build larger apps as a collection of smaller modules. For now, the modules should be npm packages that may be published (internally to Azure Artifacts).

Dynamic apps will be restricted in their contribution points and in their allowed API usage. To begin to prepare for this, modules should use the @bentley/studio-apps-frontend-api and @bentley/studio-apps-backend-api packages for Studio APIs. Apps that contain these modules can use these packages as well, in addition to the @bentley/studio-startup-apps-frontend-api and @bentley/studio-startup-apps-backend-api packages, which contain additional APIs that will not be available to modules and dynamic apps. Dynamic app APIs will likely be even more restrictive, but this is the best path towards isolating code that you wish to deliver independent of your main app code in the future.

In order to facilitate this type of iTwin Studio app development, it is a good idea to use a monorepo, where modules can be locally linked to the app in which they are imported. This allows for easier development of modules without having to publish them ahead of time. There are many monorepo tools available that aid in this type of development, including pnpm workspaces.