From 86a89c2aa5edf86c26cc580cbbfb6416b4f7d343 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 15 Jun 2026 17:09:51 +0100 Subject: [PATCH] Replace `require` calls for image uris with imports (#33847) * Replace `require` calls for image uris with imports In prep for vitest * Fix copyright --- apps/web/src/@types/png.d.ts | 11 +++++++++++ apps/web/src/SdkConfig.ts | 4 ++-- .../components/structures/static-page-vars.ts | 6 ++---- .../components/views/avatars/WidgetAvatar.tsx | 19 +++++++++++-------- .../components/views/dialogs/ShareDialog.tsx | 17 ++++++++++------- .../components/views/rooms/Stickerpicker.tsx | 5 ++--- apps/web/src/settings/Settings.tsx | 4 ++-- .../message-body/FileBodyViewModel.ts | 7 +++---- 8 files changed, 43 insertions(+), 30 deletions(-) create mode 100644 apps/web/src/@types/png.d.ts diff --git a/apps/web/src/@types/png.d.ts b/apps/web/src/@types/png.d.ts new file mode 100644 index 0000000000..97218abe19 --- /dev/null +++ b/apps/web/src/@types/png.d.ts @@ -0,0 +1,11 @@ +/* +Copyright 2026 Element Creations Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE files in the repository root for full details. +*/ + +declare module "*.png" { + const path: string; + export default path; +} diff --git a/apps/web/src/SdkConfig.ts b/apps/web/src/SdkConfig.ts index 4be64648d8..84b87e040c 100644 --- a/apps/web/src/SdkConfig.ts +++ b/apps/web/src/SdkConfig.ts @@ -13,6 +13,7 @@ import { SnakedObject } from "./utils/SnakedObject"; import { type IConfigOptions } from "./IConfigOptions"; import { isObject, objectClone } from "./utils/objects"; import { type DeepPartial, type DeepReadonly, type Defaultize } from "./@types/common"; +import ElementDesktopLogoSvg from "../res/img/element-desktop-logo.svg"; // see element-web config.md for docs, or the IConfigOptions interface for dev docs export const DEFAULTS: DeepReadonly = { @@ -44,8 +45,7 @@ export const DEFAULTS: DeepReadonly = { // be preferred over their config. desktopBuilds: { available: true, - // eslint-disable-next-line @typescript-eslint/no-require-imports - logo: require("../res/img/element-desktop-logo.svg").default, + logo: ElementDesktopLogoSvg, url: "https://element.io/get-started", }, diff --git a/apps/web/src/components/structures/static-page-vars.ts b/apps/web/src/components/structures/static-page-vars.ts index b5f21ea195..f055cd9e9f 100644 --- a/apps/web/src/components/structures/static-page-vars.ts +++ b/apps/web/src/components/structures/static-page-vars.ts @@ -6,13 +6,11 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ -// We're importing via require specifically so the svg becomes a URI rather than a DOM element. -// eslint-disable-next-line @typescript-eslint/no-require-imports -const matrixSvg = require("../../../res/img/matrix.svg").default; +import MatrixSvg from "../../../res/img/matrix.svg"; /** * Intended to replace $matrixLogo in the welcome page. */ export const MATRIX_LOGO_HTML = ` - + `; diff --git a/apps/web/src/components/views/avatars/WidgetAvatar.tsx b/apps/web/src/components/views/avatars/WidgetAvatar.tsx index 5baba7ca01..68f4221e5c 100644 --- a/apps/web/src/components/views/avatars/WidgetAvatar.tsx +++ b/apps/web/src/components/views/avatars/WidgetAvatar.tsx @@ -13,6 +13,11 @@ import classNames from "classnames"; import { type IApp, isAppWidget } from "../../../stores/WidgetStore"; import BaseAvatar, { type BaseAvatarType } from "./BaseAvatar"; import { mediaFromMxc } from "../../../customisations/Media"; +import DefaultAppSvg from "../../../../res/img/element-icons/room/default_app.svg"; +import DefaultVideoSvg from "../../../../res/img/element-icons/room/default_video.svg"; +import DefaultCalSvg from "../../../../res/img/element-icons/room/default_cal.svg"; +import DefaultDocSvg from "../../../../res/img/element-icons/room/default_doc.svg"; +import DefaultClockSvg from "../../../../res/img/element-icons/room/default_clock.svg"; interface IProps extends Omit, "name" | "url" | "urls"> { app: IApp | IWidget; @@ -20,19 +25,17 @@ interface IProps extends Omit, "name" | "url" | " } const WidgetAvatar: React.FC = ({ app, className, size = "20px", ...props }) => { - /* eslint-disable @typescript-eslint/no-require-imports */ - let iconUrls = [require("../../../../res/img/element-icons/room/default_app.svg").default]; + let iconUrl = DefaultAppSvg; // heuristics for some better icons until Widgets support their own icons if (app.type.includes("jitsi")) { - iconUrls = [require("../../../../res/img/element-icons/room/default_video.svg").default]; + iconUrl = DefaultVideoSvg; } else if (app.type.includes("meeting") || app.type.includes("calendar")) { - iconUrls = [require("../../../../res/img/element-icons/room/default_cal.svg").default]; + iconUrl = DefaultCalSvg; } else if (app.type.includes("pad") || app.type.includes("doc") || app.type.includes("calc")) { - iconUrls = [require("../../../../res/img/element-icons/room/default_doc.svg").default]; + iconUrl = DefaultDocSvg; } else if (app.type.includes("clock")) { - iconUrls = [require("../../../../res/img/element-icons/room/default_clock.svg").default]; + iconUrl = DefaultClockSvg; } - /* eslint-enable @typescript-eslint/no-require-imports */ return ( = ({ app, className, size = "20px", ...prop className={classNames("mx_WidgetAvatar", className)} // MSC2765 url={isAppWidget(app) && app.avatar_url ? mediaFromMxc(app.avatar_url).getSquareThumbnailHttp(20) : null} - urls={iconUrls} + urls={[iconUrl]} size={size} /> ); diff --git a/apps/web/src/components/views/dialogs/ShareDialog.tsx b/apps/web/src/components/views/dialogs/ShareDialog.tsx index 993c411562..02c85c1a0c 100644 --- a/apps/web/src/components/views/dialogs/ShareDialog.tsx +++ b/apps/web/src/components/views/dialogs/ShareDialog.tsx @@ -21,36 +21,39 @@ import { UIFeature } from "../../../settings/UIFeature"; import BaseDialog from "./BaseDialog"; import { type XOR } from "../../../@types/common"; import { useSettingValue } from "../../../hooks/useSettings.ts"; +import FacebookIcon from "../../../../res/img/social/facebook.png"; +import TwitterIcon from "../../../../res/img/social/twitter-2.png"; +import LinkedInIcon from "../../../../res/img/social/linkedin.png"; +import RedditIcon from "../../../../res/img/social/reddit.png"; +import EmailIcon from "../../../../res/img/social/email-1.png"; -/* eslint-disable @typescript-eslint/no-require-imports */ const SOCIALS = [ { name: "Facebook", - img: require("../../../../res/img/social/facebook.png"), + img: FacebookIcon, url: (url: string) => `https://www.facebook.com/sharer/sharer.php?u=${url}`, }, { name: "Twitter", - img: require("../../../../res/img/social/twitter-2.png"), + img: TwitterIcon, url: (url: string) => `https://twitter.com/home?status=${url}`, }, { name: "LinkedIn", - img: require("../../../../res/img/social/linkedin.png"), + img: LinkedInIcon, url: (url: string) => `https://www.linkedin.com/shareArticle?mini=true&url=${url}`, }, { name: "Reddit", - img: require("../../../../res/img/social/reddit.png"), + img: RedditIcon, url: (url: string) => `https://www.reddit.com/submit?url=${url}`, }, { name: "email", - img: require("../../../../res/img/social/email-1.png"), + img: EmailIcon, url: (url: string) => `mailto:?body=${url}`, }, ]; -/* eslint-enable @typescript-eslint/no-require-imports */ interface BaseProps { /** diff --git a/apps/web/src/components/views/rooms/Stickerpicker.tsx b/apps/web/src/components/views/rooms/Stickerpicker.tsx index 80d9422335..7bfe34b938 100644 --- a/apps/web/src/components/views/rooms/Stickerpicker.tsx +++ b/apps/web/src/components/views/rooms/Stickerpicker.tsx @@ -26,6 +26,7 @@ import type ScalarAuthClient from "../../../ScalarAuthClient"; import GenericElementContextMenu from "../context_menus/GenericElementContextMenu"; import RightPanelStore from "../../../stores/right-panel/RightPanelStore"; import { UPDATE_EVENT } from "../../../stores/AsyncStore"; +import StickerpackPlaceholder from "../../../../res/img/stickerpack-placeholder.png"; // This should be below the dialog level (4000), but above the rest of the UI (1000-2000). // We sit in a context menu, so this should be given to the context menu. @@ -200,13 +201,11 @@ export default class Stickerpicker extends React.PureComponent { }; private defaultStickerpickerContent(): JSX.Element { - // eslint-disable-next-line @typescript-eslint/no-require-imports - const imgSrc = require("../../../../res/img/stickerpack-placeholder.png"); return (

{_t("stickers|empty")}

{_t("stickers|empty_add_prompt")}

- +
); } diff --git a/apps/web/src/settings/Settings.tsx b/apps/web/src/settings/Settings.tsx index e51382ae53..e45784872b 100644 --- a/apps/web/src/settings/Settings.tsx +++ b/apps/web/src/settings/Settings.tsx @@ -55,6 +55,7 @@ import BlockInvitesConfigController from "./controllers/BlockInvitesConfigContro import RequiresSettingsController from "./controllers/RequiresSettingsController.ts"; import { type OrderedCustomSections, type CustomSectionsData } from "../stores/room-list-v3/section.ts"; import { type NotificationSound } from "../Notifier.ts"; +import VideoRoomsBetaImage from "../../res/img/betas/video_rooms.png"; export const defaultWatchManager = new WatchManager(); @@ -413,8 +414,7 @@ export const SETTINGS: Settings = { ), feedbackLabel: "video-room-feedback", feedbackSubheading: _td("labs|video_rooms_feedbackSubheading"), - // eslint-disable-next-line @typescript-eslint/no-require-imports - image: require("../../res/img/betas/video_rooms.png"), + image: VideoRoomsBetaImage, requiresRefresh: true, }, }, diff --git a/apps/web/src/viewmodels/message-body/FileBodyViewModel.ts b/apps/web/src/viewmodels/message-body/FileBodyViewModel.ts index a3d7113f1c..b86dbc1391 100644 --- a/apps/web/src/viewmodels/message-body/FileBodyViewModel.ts +++ b/apps/web/src/viewmodels/message-body/FileBodyViewModel.ts @@ -16,6 +16,8 @@ import { type FileBodyViewSnapshot, type FileBodyViewModel as FileBodyViewModelInterface, } from "@element-hq/web-shared-components"; +// eslint-disable-next-line no-restricted-imports +import DownloadSvg from "@vector-im/compound-design-tokens/icons/download.svg"; import Modal from "../../Modal"; import { _t } from "../../languageHandler"; @@ -41,10 +43,7 @@ const downloadIconCache = { url: "" }; async function cacheDownloadIcon(): Promise { if (downloadIconCache.url) return downloadIconCache.url; - // eslint-disable-next-line @typescript-eslint/no-require-imports - const svg = await fetch(require("@vector-im/compound-design-tokens/icons/download.svg").default).then((r) => - r.text(), - ); + const svg = await fetch(DownloadSvg).then((r) => r.text()); downloadIconCache.url = "data:image/svg+xml;base64," + window.btoa(svg); return downloadIconCache.url; }