diff --git a/.changeset/add-doc-environment-variables.md b/.changeset/add-doc-environment-variables.md
new file mode 100644
index 000000000..dcc1cef95
--- /dev/null
+++ b/.changeset/add-doc-environment-variables.md
@@ -0,0 +1,7 @@
+---
+'@equinor/fusion-framework-docs': patch
+---
+
+## @equinor/fusion-framework-docs
+
+Updated the "Getting started" guide with a new section about using environment variables.
diff --git a/.changeset/cookbook-environment-variables.md b/.changeset/cookbook-environment-variables.md
new file mode 100644
index 000000000..091125567
--- /dev/null
+++ b/.changeset/cookbook-environment-variables.md
@@ -0,0 +1,13 @@
+---
+"@equinor/fusion-framework-cookbook-app-react-environment-variables": major
+---
+
+## @equinor/fusion-framework-cookbook-app-react-environment-variables
+
+This new cookbook demonstrates how to use the `useAppEnvironmentVariables` hook to access environment variables in a Fusion Framework React application.
+
+The cookbook uses the newly created hook `useAppEnvironmentVariables` from `@equinor/fusion-framework-react-app` which retrieve environment variables from the application's configuration.
+
+
+
+
diff --git a/.changeset/expose-app-env.md b/.changeset/expose-app-env.md
new file mode 100644
index 000000000..7b372b93c
--- /dev/null
+++ b/.changeset/expose-app-env.md
@@ -0,0 +1,53 @@
+---
+"@equinor/fusion-framework-react-app": minor
+---
+
+## @equinor/fusion-react
+
+### What changed?
+
+The `useAppEnvironmentVariables` hook has been added to the `@equinor/fusion-react` package.
+This hook provides access to the application's environment variables, which are retrieved from the app module provided by the framework.
+
+### Why the change?
+
+Previously, there was no built-in way to access the application's environment variables from the React components.
+This new hook fills that gap, making it easier for developers to retrieve and use the environment configuration in their applications.
+
+### How to use the new feature
+
+To use the `useAppEnvironmentVariables` hook, simply import it and call it in your React component:
+
+```typescript
+import { useAppEnvironmentVariables } from '@equinor/fusion-react';
+
+const MyComponent = () => {
+ const env = useAppEnvironmentVariables<{ API_URL: string }>();
+
+ if (!env.complete) {
+ return
Loading environment variables...
;
+ }
+
+ if (env.error) {
+ return Error loading environment variables
;
+ }
+
+ return (
+
+ My environment variables: {JSON.stringify(env.value, null, 2)}
+
+ );
+};
+```
+
+
+The hook returns an observable state object that represents the current environment configuration.
+The `value` property of this object contains the environment variables, which can be typed using a generic type parameter.
+
+If the environment configuration is not yet available (e.g., during the initial load), the `complete` property will be `false`.
+If there was an error retrieving the configuration, the `error` property will be set.
+
+### Migration guide
+
+There are no breaking changes introduced with this feature. Developers can start using the `useAppEnvironmentVariables` hook immediately to access their application's environment variables.
+
diff --git a/cookbooks/app-react-environment-variables/app.config.ts b/cookbooks/app-react-environment-variables/app.config.ts
new file mode 100644
index 000000000..ecfe248f1
--- /dev/null
+++ b/cookbooks/app-react-environment-variables/app.config.ts
@@ -0,0 +1,12 @@
+// demo
+import { mergeAppConfigs, defineAppConfig } from '@equinor/fusion-framework-cli';
+export default defineAppConfig((_nev, { base }) =>
+ mergeAppConfigs(base, {
+ environment: {
+ scope: 'foobar',
+ },
+ endpoints: {
+ api: 'https://foo.bars',
+ },
+ }),
+);
diff --git a/cookbooks/app-react-environment-variables/app.manifest.config.ts b/cookbooks/app-react-environment-variables/app.manifest.config.ts
new file mode 100644
index 000000000..b895b4765
--- /dev/null
+++ b/cookbooks/app-react-environment-variables/app.manifest.config.ts
@@ -0,0 +1,7 @@
+import { defineAppManifest, mergeManifests } from '@equinor/fusion-framework-cli';
+
+export default defineAppManifest((env, { base }) => {
+ return mergeManifests(base, {
+ key: 'environment-variables',
+ });
+});
diff --git a/cookbooks/app-react-environment-variables/package.json b/cookbooks/app-react-environment-variables/package.json
new file mode 100644
index 000000000..4782f22c8
--- /dev/null
+++ b/cookbooks/app-react-environment-variables/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "@equinor/fusion-framework-cookbook-app-react-environment-variables",
+ "version": "0.0.0",
+ "description": "",
+ "private": true,
+ "type": "module",
+ "main": "src/index.ts",
+ "scripts": {
+ "build": "fusion-framework-cli app build",
+ "dev": "fusion-framework-cli app dev",
+ "docker": "cd .. && sh docker-script.sh app-react"
+ },
+ "author": "",
+ "license": "ISC",
+ "devDependencies": {
+ "@equinor/fusion-framework-cli": "workspace:^",
+ "@equinor/fusion-framework-react-app": "workspace:^",
+ "@types/react": "^18.2.50",
+ "@types/react-dom": "^18.2.7",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
+ "typescript": "^5.4.2"
+ }
+}
diff --git a/cookbooks/app-react-environment-variables/src/App.tsx b/cookbooks/app-react-environment-variables/src/App.tsx
new file mode 100644
index 000000000..232351f43
--- /dev/null
+++ b/cookbooks/app-react-environment-variables/src/App.tsx
@@ -0,0 +1,13 @@
+import { useAppEnvironmentVariables } from '@equinor/fusion-framework-react-app';
+export const App = () => {
+ const { value, complete, error } = useAppEnvironmentVariables();
+ if (!complete) {
+ return Loading...
;
+ }
+ if (error) {
+ return Error: {JSON.stringify(error, null, 2)}
;
+ }
+ return {JSON.stringify(value, null, 2)}
;
+};
+
+export default App;
diff --git a/cookbooks/app-react-environment-variables/src/config.ts b/cookbooks/app-react-environment-variables/src/config.ts
new file mode 100644
index 000000000..3e381c7bf
--- /dev/null
+++ b/cookbooks/app-react-environment-variables/src/config.ts
@@ -0,0 +1,18 @@
+import type { AppModuleInitiator } from '@equinor/fusion-framework-react-app';
+
+export const configure: AppModuleInitiator = (configurator, env) => {
+ /** print render environment arguments */
+ console.log('configuring application', env);
+
+ /** callback when configurations is created */
+ configurator.onConfigured((config) => {
+ console.log('application config created', config);
+ });
+
+ /** callback when the application modules has initialized */
+ configurator.onInitialized((instance) => {
+ console.log('application config initialized', instance);
+ });
+};
+
+export default configure;
diff --git a/cookbooks/app-react-environment-variables/src/index.ts b/cookbooks/app-react-environment-variables/src/index.ts
new file mode 100644
index 000000000..7e07c4019
--- /dev/null
+++ b/cookbooks/app-react-environment-variables/src/index.ts
@@ -0,0 +1,30 @@
+import { createElement } from 'react';
+import { createRoot } from 'react-dom/client';
+
+import { ComponentRenderArgs, makeComponent } from '@equinor/fusion-framework-react-app';
+
+import configure from './config';
+import App from './App';
+
+/** create a render component */
+const appComponent = createElement(App);
+
+/** create React render root component */
+const createApp = (args: ComponentRenderArgs) => makeComponent(appComponent, args, configure);
+
+/** Render function */
+export const renderApp = (el: HTMLElement, args: ComponentRenderArgs) => {
+ /** make render element */
+ const app = createApp(args);
+
+ /** create render root from provided element */
+ const root = createRoot(el);
+
+ /** render Application */
+ root.render(createElement(app));
+
+ /** Teardown */
+ return () => root.unmount();
+};
+
+export default renderApp;
diff --git a/cookbooks/app-react-environment-variables/tsconfig.json b/cookbooks/app-react-environment-variables/tsconfig.json
new file mode 100644
index 000000000..4c1b0a8b4
--- /dev/null
+++ b/cookbooks/app-react-environment-variables/tsconfig.json
@@ -0,0 +1,22 @@
+{
+ "extends": "../../tsconfig.base.json",
+ "compilerOptions": {
+ "rootDir": "src",
+ "jsx": "react-jsx",
+ },
+ "references": [
+ {
+ "path": "../../packages/react/app"
+ },
+ {
+ "path": "../../packages/cli"
+ },
+ ],
+ "include": [
+ "src/**/*"
+ ],
+ "exclude": [
+ "node_modules",
+ "lib"
+ ]
+}
\ No newline at end of file
diff --git a/packages/react/app/src/index.ts b/packages/react/app/src/index.ts
index cefd7eb10..60439f388 100644
--- a/packages/react/app/src/index.ts
+++ b/packages/react/app/src/index.ts
@@ -11,6 +11,7 @@ export type {
export { useAppModule } from './useAppModule';
export { useAppModules } from './useAppModules';
+export { useAppEnvironmentVariables } from './useAppEnvironmentVariables';
export { makeComponent, ComponentRenderArgs } from './make-component';
diff --git a/packages/react/app/src/useAppEnvironmentVariables.ts b/packages/react/app/src/useAppEnvironmentVariables.ts
new file mode 100644
index 000000000..51396b3fb
--- /dev/null
+++ b/packages/react/app/src/useAppEnvironmentVariables.ts
@@ -0,0 +1,54 @@
+import { useCurrentApp } from '@equinor/fusion-framework-react/app';
+import {
+ type ObservableStateReturnType,
+ useObservableSelector,
+ useObservableState,
+} from '@equinor/fusion-observable/react';
+
+/**
+ * A React hook that provides access to the application's environment variables.
+ *
+ * This hook returns an observable state object that represents the current environment configuration.
+ * The environment configuration is retrieved from the app module provided by the framework.
+ *
+ * @note This hook is only available when the app module is loaded (should be always for applications).
+ * This hook in theory should always have a value if config was provided for the application, but is async by nature, hence the `complete` and `error` properties.
+ *
+ * @example
+ * ```typescript
+ * const MyComponent = () => {
+ * const env = useAppEnvironmentVariables();
+ * if(!env.complete) {
+ * return Loading environment variables...
;
+ * }
+ * if(env.error) {
+ * return Error loading environment variables
;
+ * }
+ * return My environment variables: {JSON.stringify(env.value)}
;
+ * }
+ *
+ * @template TEnvironmentVariables - The type of the environment variables. Defaults to `unknown`.
+ * @returns An observable state object containing the current environment configuration.
+ */
+export const useAppEnvironmentVariables = <
+ TEnvironmentVariables = unknown,
+>(): ObservableStateReturnType => {
+ // Get the current app module instance from the framework
+ const app = useCurrentApp<[], TEnvironmentVariables>().currentApp;
+
+ // Ensure the app module is available before proceeding
+ if (!app) {
+ throw Error('Framework is missing app module');
+ }
+
+ // Get the environment configuration observable from the app module
+ const env$ = useObservableSelector(
+ app.getConfig(),
+ (config) => config.environment as TEnvironmentVariables,
+ );
+
+ // Return the observable state of the environment configuration
+ return useObservableState(env$, {
+ initial: app.config?.environment,
+ });
+};
diff --git a/packages/react/app/tsconfig.json b/packages/react/app/tsconfig.json
index 766989d90..e1c543767 100644
--- a/packages/react/app/tsconfig.json
+++ b/packages/react/app/tsconfig.json
@@ -9,7 +9,9 @@
},
},
"references": [
-
+ {
+ "path": "../../utils/observable"
+ },
{
"path": "../../app"
},
@@ -33,7 +35,7 @@
},
{
"path": "../widget"
- }
+ },
],
"include": [
"src/**/*"
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index be7401e65..d8042d444 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -293,6 +293,30 @@ importers:
specifier: ^5.4.2
version: 5.4.2
+ cookbooks/app-react-environment-variables:
+ devDependencies:
+ '@equinor/fusion-framework-cli':
+ specifier: workspace:^
+ version: link:../../packages/cli
+ '@equinor/fusion-framework-react-app':
+ specifier: workspace:^
+ version: link:../../packages/react/app
+ '@types/react':
+ specifier: ^18.2.50
+ version: 18.2.61
+ '@types/react-dom':
+ specifier: ^18.2.7
+ version: 18.2.19
+ react:
+ specifier: ^18.2.0
+ version: 18.2.0
+ react-dom:
+ specifier: ^18.2.0
+ version: 18.3.1(react@18.2.0)
+ typescript:
+ specifier: ^5.4.2
+ version: 5.4.5
+
cookbooks/app-react-feature-flag:
dependencies:
'@equinor/eds-core-react':
diff --git a/vue-press/src/guide/app/getting-started.md b/vue-press/src/guide/app/getting-started.md
index 0f2ee5728..2bbf241dd 100644
--- a/vue-press/src/guide/app/getting-started.md
+++ b/vue-press/src/guide/app/getting-started.md
@@ -122,6 +122,31 @@ export default () => ({
:::
+#### Environment variables
+
+To access the environment variables in the application, use the hook `useAppEnvironmentVariables` from `@equinor/fusion-framework-react-app`.
+
+```ts
+import { useAppEnvironmentVariables } from '@equinor/fusion-framework-react-app';
+
+type AppEnvironmentVariables = {
+ API_URL: string;
+ API_SCOPE: string;
+}
+
+const MyComponent = () => {
+ const env = useAppEnvironmentVariables();
+ console.log(env); // { API_URL: 'https://foo.bar', API_SCOPE: 'c5161f15-9930-4cfc-b233-e9dfc5f8ad82/.default' }
+}
+```
+
+> [!INFO]
+> The `useAppEnvironmentVariables` hook consumes asyncronous data from the app service.
+> In theory the value should always be available, since loaded during configuration.
+>
+> There will be a future module which manages application state, where during the configuration the
+> desired environment variables can be picked.
+
## Creating Application
### Main