Shared Libraries

What to reuse from erxes-api-shared, erxes-ui, and ui-modules instead of reimplementing.

For plugin patterns, see Backend Plugins and Frontend Plugins. For how these libraries connect to services and remotes, see Backend & API Gateway and Frontend & Plugin Loading.

Import boundaries

Every library is imported through package-name paths resolved by paths in tsconfig.base.json:

"paths": {
  "erxes-ui": ["frontend/libs/erxes-ui/src/index.ts"],
  "ui-modules": ["frontend/libs/ui-modules/src/index.ts"],
  "erxes-api-shared": ["backend/erxes-api-shared/src/index.ts"],
  "erxes-api-shared/*": ["backend/erxes-api-shared/src/*"]
}

The rule: use only public interfaces. Import erxes-api-shared/utils, erxes-api-shared/core-types, or erxes-api-shared/core-modules; never reach into a file's internals, copy shared source into a plugin, or import one service's implementation from another. Cross-service communication goes through the published GraphQL, tRPC, HTTP, and event APIs, or Module Federation exposes. Frontend plugins may not import from each other at all.

Backend: erxes-api-shared

Location: backend/erxes-api-shared. Its package.json declares four Preconstruct entrypoints, which define the public API:

ImportContents
erxes-api-sharedRoot entry; effectively empty, use the three subpath entries below
erxes-api-shared/utilsService bootstrap and infrastructure: startPlugin, joinErxesGateway, redis, mq-worker (sendWorkerQueue, createMQWorkerWithListeners), mongo (connection, createGenerateModels, cursor utils), apollo (wrapApolloResolvers, generateApolloContext, pagination), trpc, headers (user/subdomain propagation), logs (logHandler, after-process), file (read/upload), email, saas, sentry-init, graphqlPubSub, getEnv, getSubdomain, applyTrustProxy, createHealthRoute
erxes-api-shared/core-typesShared TypeScript types: IMainContext, IPermissionConfig, document interfaces, charge types
erxes-api-shared/core-modulesDomain modules and engines a plugin plugs into: automations, segments, logs, notifications, properties, permissions, forms, apps, users, approval, client-portals, import-export, templates, common

The library compiles with Preconstruct (pnpm nx build erxes-api-shared) into dist/ plus the utils/, core-types/, and core-modules/ entrypoint directories, which the service Dockerfiles copy into node_modules/erxes-api-shared.

Rebuild after every change

Services use the compiled output, not src/. After editing anything under backend/erxes-api-shared/src, run pnpm nx build erxes-api-shared before starting or rebuilding dependent services, or they keep running the stale build.

Frontend: erxes-ui and ui-modules

LibraryPathExports
erxes-uifrontend/libs/erxes-uiDesign-system primitives (components, lib, utils), hooks, state, types (including IUIConfig), constants, and product building blocks under modules/: board, record-table, filter, inputs, layout, display, attachments, record-field, select-tree, side-menu, preview, report, navigation-menu, focus-sheet, hotkey, icons, motion, blocks, chat-viz, select-operation. Also the shared env config (REACT_APP_API_URL, NODE_ENV) the host and remotes read
ui-modulesfrontend/libs/ui-modulesBusiness-domain UI under modules/: contacts, products, sales, segments, tags, tags-new, automations, activity-logs, internal-notes, notifications, permissions, properties, documents, favorites, import-export, approval, brands, structure, team-members, templates, header, widget, payments, shared, types, plus states (including pluginsConfigState) and hooks

Both are Module Federation shared singletons: the host and every remote share one instance, which is why Jotai state and React context written by ui-modules are visible to plugin code. Use erxes-ui for primitives, ui-modules for domain composition, and @tabler/icons-react for icons; do not hand-roll a parallel component set.

The shared-dependency list lives in two places: core-libraries.ts at the repository root (the canonical set, including radix-ui) and the coreLibraries copy inlined in each project's module-federation.config.ts. The plugin generator writes the same set into every new remote.

Path aliases

  • Frontend plugins: ~/* → src, @/* → src/modules, plus erxes-ui and ui-modules.
  • Backend services and plugins: ~/* → src, @/* → src/modules, erxes-api-shared/* → the shared library source.
Was this helpful?