Initial support for runtime modules (#29104)

* Initial runtime Modules work

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Comments

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
Michael Telatynski
2025-02-06 23:54:18 +00:00
committed by GitHub
parent 3c690e685a
commit 4a231c6450
22 changed files with 209 additions and 191 deletions

View File

@@ -31,10 +31,6 @@ import { parseQs } from "./url_utils";
import { getInitialScreenAfterLogin, getScreenFromLocation, init as initRouting, onNewScreen } from "./routing";
import { UserFriendlyError } from "../languageHandler";
// add React and ReactPerf to the global namespace, to make them easier to access via the console
// this incidentally means we can forget our React imports in JSX files without penalty.
window.React = React;
logger.log(`Application is running in ${process.env.NODE_ENV} mode`);
window.matrixLogger = logger;

View File

@@ -114,6 +114,7 @@ async function start(): Promise<void> {
loadTheme,
loadApp,
loadModules,
loadPlugins,
showError,
showIncompatibleBrowser,
_t,
@@ -159,10 +160,12 @@ async function start(): Promise<void> {
// now that the config is ready, try to persist logs
const persistLogsPromise = setupLogStorage();
// Load modules before language to ensure any custom translations are respected, and any app
// Load modules & plugins before language to ensure any custom translations are respected, and any app
// startup functionality is run
const loadModulesPromise = loadModules();
await settled(loadModulesPromise);
const loadPluginsPromise = loadPlugins();
await settled(loadPluginsPromise);
// Load language after loading config.json so that settingsDefaults.language can be applied
const loadLanguagePromise = loadLanguage();
@@ -215,6 +218,7 @@ async function start(): Promise<void> {
// app load critical path starts here
// assert things started successfully
// ##################################
await loadPluginsPromise;
await loadModulesPromise;
await loadThemePromise;
await loadLanguagePromise;

View File

@@ -11,6 +11,7 @@ Please see LICENSE files in the repository root for full details.
import { createRoot } from "react-dom/client";
import React, { StrictMode } from "react";
import { logger } from "matrix-js-sdk/src/logger";
import { ModuleLoader } from "@element-hq/element-web-module-api";
import type { QueryDict } from "matrix-js-sdk/src/utils";
import * as languageHandler from "../languageHandler";
@@ -24,6 +25,7 @@ import ElectronPlatform from "./platform/ElectronPlatform";
import PWAPlatform from "./platform/PWAPlatform";
import WebPlatform from "./platform/WebPlatform";
import { initRageshake, initRageshakeStore } from "./rageshakesetup";
import ModuleApi from "../modules/Api.ts";
export const rageshakePromise = initRageshake();
@@ -125,6 +127,9 @@ export async function showIncompatibleBrowser(onAccept: () => void): Promise<voi
);
}
/**
* @deprecated in favour of the plugin system
*/
export async function loadModules(): Promise<void> {
const { INSTALLED_MODULES } = await import("../modules.js");
for (const InstalledModule of INSTALLED_MODULES) {
@@ -132,6 +137,24 @@ export async function loadModules(): Promise<void> {
}
}
export async function loadPlugins(): Promise<void> {
// Add React to the global namespace, this is part of the new Module API contract to avoid needing
// every single module to ship its own copy of React. This also makes it easier to access via the console
// and incidentally means we can forget our React imports in JSX files without penalty.
window.React = React;
const modules = SdkConfig.get("modules");
if (!modules?.length) return;
const moduleLoader = new ModuleLoader(ModuleApi);
window.mxModuleLoader = moduleLoader;
for (const src of modules) {
// We need to instruct webpack to not mangle this import as it is not available at compile time
const module = await import(/* webpackIgnore: true */ src);
await moduleLoader.load(module);
}
await moduleLoader.start();
}
export { _t } from "../languageHandler";
export { extractErrorMessageFromError } from "../components/views/dialogs/ErrorDialog";