@equinor/echo-core

中文文档
7.0.0发布于 2026/10/27MITTypeScriptCommonJS近 30 天下载 2678

logo

原始使用文档
文档目录16 节
  1. ⚠️ Dependency Rules
  2. How to develop and release EchoCore
  3. Available NPM scripts
  4. Register application components with Setup
  5. Register App
  6. Register with Key
  7. Panels
  8. Extensions
  9. Register Page / Route
  10. Manifest
  11. Module State / Context
  12. Module Context and state
  13. RegistryState
  14. Analytics
  15. Error handling
  16. Old repository of echoCore

logo

EchoCore

Everything a Echo app needs to communicate with the core.

This publishable library was generated with Nx.

⚠️ Dependency Rules

Source of truth: /eslint.config.js - The @nx/enforce-module-boundaries rule defines all allowed dependencies.

echo-core can only import from:

  • echo-base ✅

echo-core CANNOT import from:

  • echo-framework ❌
  • echo-search ❌
  • echo-components ❌
  • echopedia-web (app) ❌

See libs/README.md for the full dependency flow diagram.


How to develop and release EchoCore

Check the readme in the NX libraries folder.

Available NPM scripts

  • lint-core
  • build-core
  • test-core

Echo Modules

Register application components with Setup

Echo is built up around modules, a module can consist of several applications, It is recommended to keep modules as small as possible preventing long loading times at application/client (Echo) startup. All modules are registered using a setup function exported from the modules entry point. This function is called at Echo startup. The function is called with the EchoModuleApi.

Register App

The api allows for app registration using registerApp as shown below. App registration is used for registration of the main application in a module, based on metadata taken from the modules manifest, the optional parameter can help with configuring the application.

Register with Key

If a module consist of several apps the second app can be registered with the registerAppWithKey function. this lets you manually register an app, so remember some configuration is needed here.

Panels

registerPanels is for registering panels with a provided key. This key must correspond to a path which is registered. The path is used to trigger the loading ot the panels automatically. if not it need to be triggered by the setActiveModulePanels Action.Application panels can also be added when using registerApp, this can be done trough the AppOptions.

Extensions

Extensions are meant to extend or augment different, existing components in the EchopediaWeb core application or in EchoFramework - this gives the system flexibility. How the given extensions are handled is always up to the extendable component. EchoCore just provides the architecture for this.

Example:

There's a list of application links (both internal and external) in EchopediaWeb's Tag search results, in a TagItem's header - with this we can open a tag in a different app. This component was built to be extendable: it will connect EchoCore state and render additional links based on the registered extensions for this component in EchoCore.

Here's how an EchoModule can register it's own link into this particular component, with the help of a dedicated registerContextualAppLink() function:

// Register a simple, icon button component.
// It will handle simple linking to your app with the given tag.
export function setup(api: EchoModuleApi): void {
    api.registerPage('/myEchoModule', MyEchoModule);
    api.registerContextualAppLink({
        label: 'Open in Awesome Echo App',
        iconName: 'rotate_3d' // accepts EDS icon names
    });
}

// For more complex scenarios: Register a custom button component, which uses it's own logic to navigate to your app.
import { MyCustomLinkButton } from './MyCustomLinkButton';

export function setup(api: EchoModuleApi): void {
    api.registerPage('/myEchoModule', MyEchoModule);
    api.registerContextualAppLink({
        component: MyCustomLinkButton
    });
}

The above mentioned extensions are utilized by ContextualAppLinks component, which can be found in EchoFramework. Check it out to learn more about it!

It is also possible to register a custom extension either by using registerApp through AppOptions or by using the setup function, EchoModuleApi:

export function setup(api: EchoModuleApi): void {
    api.registerPage('/myEchoModule', MyEchoModule);
    api.registerExtension({
        key: 'unique-key',
        extends: 'PredifenedComponentName',
        component: MyCustomExtensionComponent,
        options: { // custom options used by the extendable component
            listOfUsers: [ 'Mary Sue', 'John Doe' ]
            isApproved: false,
            ...
        }
    })
}

Each extendable component utilizes it's extensions in a unique way: if you want to use registerExtension() function, make sure you're familiar with the required options for the given, extendable component.

A component can have any number of extensions.

The useExtensions() hook can help you with getting all the registered extensions for a given component.

Extensions are stored in the GlobalState.registry.extensions;

Register Page / Route

Under the hood registerRoute is what registerApp, registerAppWithKey, and registerPage, uses. An app is just a route with a added component. registerPag can be used to register pages which needs no direct connection.

import { EchoModuleApi, PanelType } from "@equinor/echo-core"
import { Icon, themeConst } from '@equinor/echo-components';
import TestModule from "./testModule";
import Panel from "./panel";

export function setup(api: EchoModuleApi): void {
    const icon = (): JSX.Element => <Icon color={themeConst.equiGreen1} name='tag' />;

    api.registerApp(TestModule, {
        homeScreen: true,
        panels: { component: Panel, key: 'test', icon, label: 'test', panelType: PanelType.left }
    });
}

Manifest

As you can see in the code sample above, TestModule module is registered as an app. The app will register a route and link this using the modules appManifest. here is an example of such manifest.

        {
            name: 'Test',
            requireRef: '',
            key: 'test',
            shortName: 'test',
            path: '/test',
            fileUri: 'echo-test-module.js',
            version: '0.0.1',
        }

Global State

The global state is meant for application related data. Large data sets will slow down the performance of the application / client so keeping this to the minimum is key. Lets take a look at at current global state.


interface GlobalState {
    app: EchoAppState;
    modules: Array<AppModule>;
    coreComponents: EchoCoreComponents;
    registry: RegistryState;
    ui: Dict<UI>;
    userProfile?: User;
    userPhotoUrl?: string;
    legendOptions: LegendOptions;
    settings: Settings;
    plantsData: PlantsData;
    procosysProjectsData: ProcosysProjectsData;
    moduleState: EchoCustomState<unknown>;
    moduleContext: ModuleContext<unknown>;
}

There are three sections which are particularly interesting, the registry, moduleState and moduleContext. First let's look at module state and context.

Module State / Context

Echo core provides two ways of utilizing the module state. The first method using just the moduleState. the state can be initialized and retrieve with useAppModuleState.

interface State {
    data: string
    name: string;
    lastName: string
}

const state = {
    data: "This is a module state",
    name: "Tom",
    lastName: "Jones"
}

// This will register the module state
useAppModuleState(state);

// To retrieve the module state with types one can write.
const { name, lastName } = useAppModuleState<State>();

There are several ways to update the module state.


const newState = {
    data: "using the updateModuleState will replace the current state";
    name: "Tom",
    lastName: "Jones",
}

updateModuleState(newState);

// This will update just the name property of the module State.
updateSpecificModuleState("name", "John");

Module Context and state

The state can be use in conjunction with a context the context is wrapping the whole application this can be sean in EchoContent.tsx file in EchoFramework. The ModuleContextProvider is provided form EchoCore, will always provide the current moduleState. This will allow you to use regular react context.

Use to communicate with panels and header!

import { ModuleContextProvider } from '@equinor/echo-core';
import React from 'react';
import { LayoutProps } from '../components';
import CorePanelLeft from '../components/panel/corePanelLeft';
import CorePanelRight from '../components/panel/corePanelRight';

interface CorePanelsProps {
    children: React.ReactNode;
    Legend?: React.FC;
}


export const EchoContent: React.FC<CorePanelsProps> = ({ children, Legend }: CorePanelsProps): JSX.Element => {
    return (
        <ModuleContextProvider>
            <CorePanelLeft />
            <CorePanelRight />
            {children}
            {Legend && <Legend />}
        </ModuleContextProvider>
    );
};

A context can be registered by using the registerModuleContext function provided by EchoCore.

RegistryState

This is the the Echo global app sub-state container for registering application components. This state is the most important state of the whole application and contains all routes, panels and appLinks.

As EchoCore' responsibility is mainly to provide developers the tools to register and retrieve information form the global state the usage of the RegistryState can be found in EchoFramework's documentation which can be found here

Analytics

Logging to Application Insights.

Analytics general info in runbook here

Create the logging module with:

const analyticsLog = analytics.createAnalyticsModule("ep");

Optional static event or error properties can also be attached to all events or errors with:

const analyticsLog = analytics.createAnalyticsModule("ep", { staticEventProperties: {ver: 1.01}, staticErrorProperties: {ver: 1.01} });

Log event with:

    analyticsLog.trackEvent(event: AnalyticsEvent)
    analyticsLog.trackEventBy(objectName: string, actionName: string, properties: AnalyticsPropertyTypes)

    analyticsLog.trackEventBy("Document", "Opened", {docNo: "abc123", fileId: 12345 })

The format in Application Insights will be:

  • appId.Object.Action
  • appId_subModule.Object.Action
  • ep.Pdf.Opened
  • ep.Document.Opened
  • ep_3d.Viewer.ClickedTag

Error logging should usually not be called directly. Instead use handleError (TODO - update this documentation when we have handleError in core), which will report the error to appInsight.

    analyticsLog.logError(error)

Echo-inField should in addition do some configuration, like setting user, instCode and company, which will be supplied with each event.

    analyticsConfiguration

Error handling

Error Reporting to application insight.
Register a helper function errorHandler like this:

export const errorHandler = (exception: Error | BaseError): void => {
    EchoCore.handleErrors(exception, myModuleAnalyticsModule);
};

BaseError extends Error, and is recommended to use instead of Error

  • It makes sure that that the error is only logged once to appInsights
  • All properties of BaseError are logged to AppInsights, even if they are private
  • It supports innerError, either as type Error or Record<string, unknown>

Use the toError helper function for converting a caught unknown to a proper Error object.

It's recommended to extend BaseError, and decorate it with extra properties, as seen in the example below.

Example of a customError and typical error flow.

    export class PdfError extends BaseError {
        docNo: string;
        constructor(args: { message: string; docNo: string; innerError?: Error }) {
            super({ name: 'PdfError', message: args.message, innerError: args.innerError });
            this.docNo = args.docNo;
        }
    }
    ...

    try {
        loadPdf();
    } catch(error) {
        throw new PdfError({ message:"load pdf failed", docNo: "a-73", innerError: toError(error) });
    }
}

Old repository of echoCore

Keeping it for historical reasons. https://github.com/equinor/EchoCore and before that, https://github.com/equinor/EchoFramework

版本与发布记录

@equinor/echo-core 共发布 245 个版本,首次发布于 2020/12/05;过去 12 个月发布了 36 个版本。

版本发布日期距今
7.0.0latest2026/10/2717 天前
7.0.0-beta-2beta2026/10/2717 天前
7.0.0-beta-12026/10/2222 天前
7.0.0-beta-02026/10/2024 天前
6.3.12026/08/073 个月前
6.3.02026/07/233 个月前

其他发布通道:next → 0.7.3-rc0,beta → 7.0.0-beta-2。

关于 @equinor/echo-core 的常见问题

如何安装 @equinor/echo-core?

在项目目录运行 npm install @equinor/echo-core,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(>= 19.2.4)、zustand(>= 4.4.7 < 5)、react-router-dom(>= 6.30.3 < 7)、@equinor/echo-base(>= 7.0.0 < 8.0.0)、@tanstack/react-query(>= 5.24.1 < 6)、@microsoft/microsoft-graph-types(2.43.1)、@microsoft/microsoft-graph-types-beta(0.44.0-preview)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@equinor/echo-core 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@equinor/echo-core 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@equinor/echo-core 可以商用吗?

@equinor/echo-core 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@equinor/echo-core 的下载量有多少?

根据 npm 官方下载统计,@equinor/echo-core 在 2026/10/14 – 2026/11/12 这 30 天内被下载 2,678 次,日均约 89 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@equinor/echo-core 还在维护吗?

最新版本 7.0.0 发布于 2026/10/27(17 天前);至今共发布 245 个版本,其中过去 12 个月发布了 36 个;首次发布于 2020/12/05。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。