PluginEngine resolves enabled plugins in two stages:
- It fetches plugin configs from
GET /api/v1/plug_config/. - It merges that API response with build-time plugins from
careConfig.careApps(derived fromREACT_ENABLED_APPS).
The merged list is the effective plugin set used by the frontend. Build-time plugins act as the base enabled plugins, so they load even when the backend does not return a matching plug_config row.
Build-time plugin identity:
REACT_ENABLED_APPSis parsed bycare.config.tsintocareConfig.careApps.- Each build-time plugin is normalized into the same
PlugConfigshape as the API response bysrc/Utils/plugConfig.ts. - The resolved
slugfor a build-time plugin is the parsed pluginnamefield, which is typically the repository name.
REACT_ENABLED_APPS format:
- Each entry is expected in the form
org/repoororg/repo@host/path/to/remoteEntry.js. - If
@host/pathis omitted, CARE defaults to GitHub Pages:https://{org}.github.io/{repo}. - If the host contains
localhost, CARE prefixes it withhttp://; otherwise it prefixes it withhttps://. - In host dev mode, CARE auto-discovers valid local plugin apps from
apps/*/src/manifest.*(any TS/JS extension) and loads them directly through the host Vite graph. - Example remote entry for non-hosted local testing or preview flows:
ohcnetwork/care_hello_fe@localhost:4173/assets/remoteEntry.js.
Merge behavior:
- API-only plugins remain editable and keep
source: "api". - Build-time plugins are always marked
source: "build"andisReadOnly: true. - If both sources provide the same slug, the frontend keeps one merged entry for that slug.
- For overlapping metadata keys, build-time metadata wins.
- API-only metadata keys that do not conflict are preserved.
For each resolved plugin config, PluginEngine:
- Validates
config.meta.url. - Registers the remote with Vite federation using the plugin
slug. - Loads
./manifestfrom the remote. - Combines the manifest with
config.metaand exposes the frozen metadata onwindow.__CARE_PLUGIN_RUNTIME__.meta. - Registers plugin overrides through
addOverride(...). - Makes the loaded manifests available through
CareAppsContext.
Failure behavior:
- If
config.meta.urlis missing or invalid, the plugin is logged and skipped. - If the remote manifest cannot be loaded, the plugin is logged and skipped.
- These failures do not prevent the rest of the app or other plugins from loading.
PLUGIN_Component renders plugin-provided React components by looking them up in each loaded manifest's components map.
initI18n() also uses the same merged plugin-config list to discover plugin namespaces and translation origins. If the plug_config API call fails, the app still falls back to build-time plugins for i18n namespace discovery.
Admin UI behavior:
- API-backed plugin configs remain editable.
- Build-time plugins are shown in the PlugConfig admin page as built-in, read-only entries.
- Direct navigation to a build-time plugin's edit route opens a read-only detail view backed by the build-time config and skips the backend
GET /api/v1/plug_config/{slug}/request. - Those built-in entries are still loaded by runtime code even without editable backend state.
Testing guidance:
- If a plugin should always be present during tests, add it to
REACT_ENABLED_APPSso it becomes a build-time base plugin. - If a test needs backend-managed plugin metadata only, seed the
plug_configAPI response. - If both sources define the same plugin slug, the frontend keeps the plugin enabled as a build-time plugin and merges API-only metadata keys with the build-time metadata.
- For local host development with the sample hello-world plugin in
apps/care_hello_fe, start the main app withnpm run dev. CARE auto-enables local plugins discovered underapps/and serves theirpublic/assets from the host dev server. - For remote-style testing or preview flows, a working entry remains
ohcnetwork/care_hello_fe@localhost:4173/assets/remoteEntry.js, and the sample plugin can still be run fromapps/care_hello_fewithnpm run dev.
Host-to-plugin data sharing via window globals (set in src/index.tsx):
window.CARE_API_URL— The backend API base URL (careConfig.apiUrl). Plugins use this to make API calls without importing host modules.window.AuthUserContext— The React context object for auth state (AuthUserContext). Sincereactis a shared dependency, plugins can callReact.useContext(window.AuthUserContext)to accesssignIn,signOut,user, etc., because the plugin component tree renders inside the host'sAuthUserProvider.window.__CORE_ENV__— The fullcareConfigobject (API URLs, feature flags, locale settings, plugin config).window.__CARE_PLUGIN_RUNTIME__— Plugin-specific runtime metadata ({ meta: PlugConfigMeta }) set byPluginEngineafter the plugin manifest loads.