Skip to content

Commit

Permalink
Reduce bundle size for widget room configs (#985)
Browse files Browse the repository at this point in the history
* Add dynamic imports for room configs.

* Try to move code editor to imports

* Load code editor on demand to save a bundle load.

* Load fonts from npm

* changelog

* lint
  • Loading branch information
Half-Shot authored Nov 19, 2024
1 parent f630bcc commit f0651a6
Show file tree
Hide file tree
Showing 28 changed files with 82 additions and 219 deletions.
1 change: 1 addition & 0 deletions changelog.d/987.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Reduce bundle size of widget.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
},
"devDependencies": {
"@codemirror/lang-javascript": "^6.0.2",
"@fontsource/inter": "^5.1.0",
"@napi-rs/cli": "^2.13.2",
"@preact/preset-vite": "^2.2.0",
"@rollup/plugin-alias": "^5.1.0",
Expand Down
28 changes: 10 additions & 18 deletions web/components/RoomConfigView.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
import { lazy, Suspense } from "preact/compat"
import { useState } from "preact/hooks"
import { BridgeConfig, EmbedType } from "../BridgeAPI";
import style from "./RoomConfigView.module.scss";
import { ConnectionCard } from "./ConnectionCard";
import { FeedsConfig } from "./roomConfig/FeedsConfig";
import { GenericWebhookConfig } from "./roomConfig/GenericWebhookConfig";
import { OutboundWebhookConfig } from "./roomConfig/OutboundWebhookConfig";
import { GithubRepoConfig } from "./roomConfig/GithubRepoConfig";
import { GitlabRepoConfig } from "./roomConfig/GitlabRepoConfig";
import { JiraProjectConfig } from "./roomConfig/JiraProjectConfig";

import FeedsIcon from "../icons/feeds.png";
import GitHubIcon from "../icons/github.png";
import GitLabIcon from "../icons/gitlab.png";
Expand Down Expand Up @@ -46,40 +40,40 @@ const connections: Record<ConnectionType, IConnectionProps> = {
displayName: "RSS/Atom Feeds",
description: "Subscribe to an RSS/Atom feed",
icon: FeedsIcon,
component: FeedsConfig,
component: lazy(() => import("./roomConfig/FeedsConfig")),
},
[ConnectionType.Github]: {
displayName: 'Github',
description: "Connect the room to a GitHub project",
icon: GitHubIcon,
darkIcon: true,
component: GithubRepoConfig,
component: lazy(() => import("./roomConfig/GithubRepoConfig")),
},
[ConnectionType.Gitlab]: {
displayName: 'Gitlab',
description: "Connect the room to a GitLab project",
icon: GitLabIcon,
component: GitlabRepoConfig,
component: lazy(() => import("./roomConfig/GitlabRepoConfig")),
},
[ConnectionType.Jira]: {
displayName: 'JIRA',
description: "Connect the room to a JIRA project",
icon: JiraIcon,
component: JiraProjectConfig,
component: lazy(() => import("./roomConfig/JiraProjectConfig")),
},
[ConnectionType.Generic]: {
displayName: 'Inbound (Generic) Webhook',
description: "Create a webhook which can be used to connect any service to Matrix",
icon: WebhookIcon,
darkIcon: true,
component: GenericWebhookConfig,
component: lazy(() => import("./roomConfig/GenericWebhookConfig")),
},
[ConnectionType.GenericOutbound]: {
displayName: 'Outbound Webhook',
description: "Create a webhook which can be used to connect any service to Matrix",
icon: WebhookIcon,
darkIcon: true,
component: OutboundWebhookConfig,
component: lazy(() => import("./roomConfig/OutboundWebhookConfig")),
},
};

Expand All @@ -91,10 +85,9 @@ export default function RoomConfigView(props: IProps) {

if (activeConnectionType) {
const ConfigComponent = connections[activeConnectionType].component;
content = <ConfigComponent
roomId={props.roomId}
showHeader={props.embedType !== EmbedType.IntegrationManager}
/>;
content = <Suspense fallback="loading">
<ConfigComponent roomId={props.roomId} showHeader={props.embedType !== EmbedType.IntegrationManager} />
</Suspense>;
} else {
content = <>
<section>
Expand All @@ -115,7 +108,6 @@ export default function RoomConfigView(props: IProps) {
}

return <div className={style.root}>

{!serviceScope && activeConnectionType &&
<header>
<span className={style.backButton} onClick={() => setActiveConnectionType(null)}>
Expand Down
5 changes: 3 additions & 2 deletions web/components/roomConfig/FeedsConfig.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,7 @@ const roomConfigText: IRoomConfigText = {

const RoomConfigListItemFunc = (c: FeedResponseItem) => c.config.label || c.config.url;

export const FeedsConfig: BridgeConfig = ({ roomId, showHeader }) => {

const FeedsConfig: BridgeConfig = ({ roomId, showHeader }) => {
return <RoomConfig<ServiceConfig, FeedResponseItem, FeedConnectionState>
headerImg={FeedsIcon}
showHeader={showHeader}
Expand All @@ -105,3 +104,5 @@ export const FeedsConfig: BridgeConfig = ({ roomId, showHeader }) => {
connectionConfigComponent={ConnectionConfiguration}
/>;
};

export default FeedsConfig;
73 changes: 46 additions & 27 deletions web/components/roomConfig/GenericWebhookConfig.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { FunctionComponent, createRef } from "preact";
import { useCallback, useEffect, useState } from "preact/hooks"
import CodeMirror from '@uiw/react-codemirror';
import { javascript } from '@codemirror/lang-javascript';
import { add, format } from "date-fns";
import { BridgeConfig } from "../../BridgeAPI";
import type { GenericHookConnectionState, GenericHookResponseItem, GenericHookServiceConfig } from "../../../src/Connections/GenericHook";
Expand All @@ -10,6 +8,12 @@ import { InputField, ButtonSet, Button } from "../elements";
import WebhookIcon from "../../icons/webhook.png";
import { Alert, ToggleInput } from "@vector-im/compound-web";
import { InfoIcon, WarningIcon } from "@vector-im/compound-design-tokens/assets/web/icons"
import { lazy, Suspense } from "preact/compat";
import { LoadingSpinner } from "../elements/LoadingSpinner";
import { Extension } from "@uiw/react-codemirror";


const CodeMirror = lazy(() => import("@uiw/react-codemirror"));

const EXAMPLE_SCRIPT = `if (data.counter === undefined) {
result = {
Expand All @@ -29,10 +33,46 @@ const EXAMPLE_SCRIPT = `if (data.counter === undefined) {
}`;

const DOCUMENTATION_LINK = "https://matrix-org.github.io/matrix-hookshot/latest/setup/webhooks.html#script-api";
const CODE_MIRROR_EXTENSIONS = [javascript({})];

const EXPIRY_WARN_AT_MS = 3 * 24 * 60 * 60 * 1000;

const CodeEditor: FunctionComponent<{value: string, onChange: (value: string) => void}> = ({value, onChange}) => {
const [codeMirrorTheme, setCodeMirrorTheme] = useState<"light"|"dark">("light");
const [extensions, setExtensions] = useState<Extension[]>();
useEffect(() => {
const mm = window.matchMedia('(prefers-color-scheme: dark)');
const fn = (event: MediaQueryListEvent) => {
setCodeMirrorTheme(event.matches ? "dark" : "light");
};
mm.addEventListener('change', fn);
setCodeMirrorTheme(mm.matches ? "dark" : "light");
return () => mm.removeEventListener('change', fn);
}, []);

useEffect(() => {
async function loader() {
const { javascript } = await import("@codemirror/lang-javascript");
setExtensions([javascript({ jsx: false, typescript: false})]);
console.log('Extensions loaded');
}
void loader();
}, []);

if (!extensions) {
return <LoadingSpinner />;
}

return <Suspense fallback={<LoadingSpinner />}>
<CodeMirror
value={value}
theme={codeMirrorTheme}
extensions={extensions}
onChange={onChange}
/>
<p> See the <a target="_blank" rel="noopener noreferrer" href={DOCUMENTATION_LINK}>documentation</a> for help writing transformation functions </p>
</Suspense>;
};

const ConnectionConfiguration: FunctionComponent<ConnectionConfigurationProps<GenericHookServiceConfig, GenericHookResponseItem, GenericHookConnectionState>> = ({serviceConfig, existingConnection, onSave, onRemove, isUpdating}) => {
const [transFn, setTransFn] = useState<string>(existingConnection?.config.transformationFunction as string || EXAMPLE_SCRIPT);
const [transFnEnabled, setTransFnEnabled] = useState(serviceConfig.allowJsTransformationFunctions && !!existingConnection?.config.transformationFunction);
Expand All @@ -58,21 +98,6 @@ const ConnectionConfiguration: FunctionComponent<ConnectionConfigurationProps<Ge
});
}, [expiryRef, canEdit, onSave, nameRef, transFn, existingConnection, transFnEnabled, waitForComplete]);

const [codeMirrorTheme, setCodeMirrorTheme] = useState<"light"|"dark">("light");
useEffect(() => {
if (!transFnEnabled) {
return;
}
const mm = window.matchMedia('(prefers-color-scheme: dark)');
const fn = (event: MediaQueryListEvent) => {
setCodeMirrorTheme(event.matches ? "dark" : "light");
};
mm.addEventListener('change', fn);
setCodeMirrorTheme(mm.matches ? "dark" : "light");
return () => mm.removeEventListener('change', fn);
}, [transFnEnabled]);


const hasExpired = existingConnection?.secrets?.timeRemainingMs ? existingConnection?.secrets?.timeRemainingMs <= 0 : false;
const willExpireSoon = !hasExpired && existingConnection?.secrets?.timeRemainingMs ? existingConnection?.secrets?.timeRemainingMs <= EXPIRY_WARN_AT_MS : false;

Expand Down Expand Up @@ -123,15 +148,7 @@ const ConnectionConfiguration: FunctionComponent<ConnectionConfigurationProps<Ge
<InputField visible={serviceConfig.allowJsTransformationFunctions && transFnEnabled} label="Respond after function completes" noPadding={true}>
<ToggleInput disabled={!canEdit || serviceConfig.waitForComplete} type="checkbox" checked={waitForComplete || serviceConfig.waitForComplete} onChange={useCallback(() => setWaitForComplete(v => !v), [])} />
</InputField>

{transFnEnabled && <><CodeMirror
value={transFn}
theme={codeMirrorTheme}
extensions={CODE_MIRROR_EXTENSIONS}
onChange={setTransFn}
/>
<p> See the <a target="_blank" rel="noopener noreferrer" href={DOCUMENTATION_LINK}>documentation</a> for help writing transformation functions </p>
</>}
{transFnEnabled && <CodeEditor value={transFn} onChange={setTransFn} />}
<ButtonSet>
{ canEdit && <Button disabled={isUpdating} type="submit">{ existingConnection ? "Save" : "Add Webhook" }</Button>}
{ canEdit && existingConnection && <Button disabled={isUpdating} intent="remove" onClick={onRemove}>Remove Webhook</Button>}
Expand Down Expand Up @@ -173,3 +190,5 @@ export const GenericWebhookConfig: BridgeConfig = ({ roomId, showHeader }) => {
connectionConfigComponent={ConnectionConfiguration}
/>;
};

export default GenericWebhookConfig;
4 changes: 3 additions & 1 deletion web/components/roomConfig/GithubRepoConfig.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ const roomConfigText: IRoomConfigText = {

const RoomConfigListItemFunc = (c: GitHubRepoResponseItem) => getRepoFullName(c.config);

export const GithubRepoConfig: BridgeConfig = ({ roomId, showHeader }) => {
const GithubRepoConfig: BridgeConfig = ({ roomId, showHeader }) => {
return <RoomConfig<never, GitHubRepoResponseItem, GitHubRepoConnectionState>
headerImg={GitHubIcon}
darkHeaderImg={true}
Expand All @@ -191,3 +191,5 @@ export const GithubRepoConfig: BridgeConfig = ({ roomId, showHeader }) => {
connectionConfigComponent={ConnectionConfiguration}
/>;
};

export default GithubRepoConfig;
4 changes: 3 additions & 1 deletion web/components/roomConfig/GitlabRepoConfig.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ const RoomConfigText = {

const RoomConfigListItemFunc = (c: GitLabRepoResponseItem) => c.config.path;

export const GitlabRepoConfig: BridgeConfig = ({ roomId, showHeader }) => {
const GitlabRepoConfig: BridgeConfig = ({ roomId, showHeader }) => {
return <RoomConfig<never, GitLabRepoResponseItem, GitLabRepoConnectionState>
headerImg={GitLabIcon}
showHeader={showHeader}
Expand All @@ -138,3 +138,5 @@ export const GitlabRepoConfig: BridgeConfig = ({ roomId, showHeader }) => {
connectionConfigComponent={ConnectionConfiguration}
/>;
};

export default GitlabRepoConfig;
4 changes: 3 additions & 1 deletion web/components/roomConfig/JiraProjectConfig.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ const RoomConfigText = {

const RoomConfigListItemFunc = (c: JiraProjectResponseItem) => c.config.url;

export const JiraProjectConfig: BridgeConfig = ({ roomId, showHeader }) => {
const JiraProjectConfig: BridgeConfig = ({ roomId, showHeader }) => {
return <RoomConfig<never, JiraProjectResponseItem, JiraProjectConnectionState>
headerImg={JiraIcon}
showHeader={showHeader}
Expand All @@ -122,3 +122,5 @@ export const JiraProjectConfig: BridgeConfig = ({ roomId, showHeader }) => {
connectionConfigComponent={ConnectionConfiguration}
/>;
};

export default JiraProjectConfig;
4 changes: 3 additions & 1 deletion web/components/roomConfig/OutboundWebhookConfig.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ const RoomConfigText = {

const RoomConfigListItemFunc = (c: OutboundHookResponseItem) => c.config.name;

export const OutboundWebhookConfig: BridgeConfig = ({ roomId, showHeader }) => {
const OutboundWebhookConfig: BridgeConfig = ({ roomId, showHeader }) => {
return <RoomConfig<ServiceConfig, OutboundHookResponseItem, OutboundHookConnectionState>
headerImg={WebhookIcon}
darkHeaderImg={true}
Expand All @@ -83,3 +83,5 @@ export const OutboundWebhookConfig: BridgeConfig = ({ roomId, showHeader }) => {
connectionConfigComponent={ConnectionConfiguration}
/>;
};

export default OutboundWebhookConfig;
Binary file removed web/fonts/Inter/Inter-Bold.woff
Binary file not shown.
Binary file removed web/fonts/Inter/Inter-Bold.woff2
Binary file not shown.
Binary file removed web/fonts/Inter/Inter-BoldItalic.woff
Binary file not shown.
Binary file removed web/fonts/Inter/Inter-BoldItalic.woff2
Binary file not shown.
Binary file removed web/fonts/Inter/Inter-Italic.woff
Binary file not shown.
Binary file removed web/fonts/Inter/Inter-Italic.woff2
Binary file not shown.
Binary file removed web/fonts/Inter/Inter-Medium.woff
Binary file not shown.
Binary file removed web/fonts/Inter/Inter-Medium.woff2
Binary file not shown.
Binary file removed web/fonts/Inter/Inter-MediumItalic.woff
Binary file not shown.
Binary file removed web/fonts/Inter/Inter-MediumItalic.woff2
Binary file not shown.
Binary file removed web/fonts/Inter/Inter-Regular.woff
Binary file not shown.
Binary file removed web/fonts/Inter/Inter-Regular.woff2
Binary file not shown.
Binary file removed web/fonts/Inter/Inter-SemiBold.woff
Binary file not shown.
Binary file removed web/fonts/Inter/Inter-SemiBold.woff2
Binary file not shown.
Binary file removed web/fonts/Inter/Inter-SemiBoldItalic.woff
Binary file not shown.
Binary file removed web/fonts/Inter/Inter-SemiBoldItalic.woff2
Binary file not shown.
93 changes: 0 additions & 93 deletions web/fonts/OFL.txt

This file was deleted.

Loading

0 comments on commit f0651a6

Please sign in to comment.