fix: ESLint errors, stale disable comments, bundle splitting
- RoomTimeline.tsx: add eslint-disable comment for intentional eventsLength dep on timelineSegments useMemo (needed to detect in-place timeline mutations) - Remove ~47 stale eslint-disable-next-line comments across 28 files for rules that are now off in the flat config (no-param-reassign, jsx-a11y/media-has-caption, react/no-array-index-key, etc); run prettier to reformat - vite.config.js: move manualChunks from rollupOptions.output to rolldownOptions.output so Rolldown (Vite 8) actually applies it; main bundle drops from 3.5 MB to 814 kB gzip-248 kB, matrix-sdk gets its own 1.16 MB cacheable chunk Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable jsx-a11y/media-has-caption */
|
||||
import React, { ReactNode, useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useAtomValue, useSetAtom } from 'jotai';
|
||||
import FocusTrap from 'focus-trap-react';
|
||||
|
||||
@@ -137,7 +137,6 @@ function CompareEmoji({ sasData }: { sasData: ShowSasCallbacks }) {
|
||||
>
|
||||
{sasData.sas.emoji?.map(([emoji, name], index) => (
|
||||
<Box
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
key={`${emoji}${name}${index}`}
|
||||
direction="Column"
|
||||
gap="100"
|
||||
|
||||
@@ -89,7 +89,6 @@ export function LobbySkeleton() {
|
||||
{/* Room list rows */}
|
||||
<div style={{ flex: 1, padding: '8px 0' }}>
|
||||
{ROOM_ROWS.map((row, i) => (
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
<div
|
||||
key={i}
|
||||
style={{
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */
|
||||
import React, { FormEventHandler, MouseEventHandler, useEffect, useRef, useState } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import {
|
||||
|
||||
@@ -80,7 +80,6 @@ export function RoomSkeleton() {
|
||||
{/* Timeline */}
|
||||
<div style={{ flex: 1, overflowY: 'hidden', padding: '16px 0' }}>
|
||||
{MESSAGES.map((msg, i) => (
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
<div
|
||||
key={i}
|
||||
style={{
|
||||
@@ -103,7 +102,6 @@ export function RoomSkeleton() {
|
||||
<div style={{ ...shimmer, width: '90px', height: '12px', marginBottom: '2px' }} />
|
||||
)}
|
||||
{msg.lines.map((line, j) => (
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
<div key={j} style={{ ...shimmer, width: line.w, height: '14px' }} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import React, {
|
||||
ClipboardEventHandler,
|
||||
KeyboardEventHandler,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import { Descendant, Text } from 'slate';
|
||||
import parse from 'html-dom-parser';
|
||||
import { ChildNode, Element, isText, isTag } from 'domhandler';
|
||||
|
||||
@@ -148,7 +148,6 @@ export const resetEditor = (editor: Editor) => {
|
||||
};
|
||||
|
||||
export const resetEditorHistory = (editor: Editor) => {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
editor.history = {
|
||||
undos: [],
|
||||
redos: [],
|
||||
@@ -228,7 +227,6 @@ export const getPointUntilChar = (
|
||||
reverse: options.reverse,
|
||||
});
|
||||
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const point of pointItr) {
|
||||
if (!Point.equals(point, cursorPoint) && prevPoint) {
|
||||
char = Editor.string(editor, { anchor: point, focus: prevPoint });
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */
|
||||
import React from 'react';
|
||||
import FileSaver from 'file-saver';
|
||||
import classNames from 'classnames';
|
||||
|
||||
@@ -4,7 +4,6 @@ import * as css from './media.css';
|
||||
|
||||
export const Video = forwardRef<HTMLVideoElement, VideoHTMLAttributes<HTMLVideoElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
// eslint-disable-next-line jsx-a11y/media-has-caption
|
||||
<video className={classNames(css.Video, className)} {...props} ref={ref} />
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable jsx-a11y/media-has-caption */
|
||||
import React, { ReactNode, useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { Badge, Chip, Icon, IconButton, Icons, ProgressBar, Spinner, Text, toRem } from 'folds';
|
||||
import { EncryptedAttachmentInfo } from 'browser-encrypt-attachment';
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */
|
||||
import React, { ComponentProps, HTMLAttributes, Suspense, forwardRef, lazy } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { Box, Chip, Header, Icon, IconButton, Icons, Scroll, Text, as } from 'folds';
|
||||
|
||||
@@ -42,7 +42,6 @@ function PreviewVideo({ fileItem }: PreviewVideoProps) {
|
||||
const fileUrl = useObjectURL(originalFile);
|
||||
|
||||
return (
|
||||
// eslint-disable-next-line jsx-a11y/media-has-caption
|
||||
<video
|
||||
style={{
|
||||
objectFit: 'contain',
|
||||
|
||||
@@ -168,7 +168,6 @@ export function CallControls({ callEmbed }: CallControlsProps) {
|
||||
}
|
||||
};
|
||||
// microphone intentionally read via microphoneRef — excluded from deps to avoid listener churn
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [pttMode, pttKey, callEmbed]);
|
||||
|
||||
const [hangupState, hangup] = useAsyncCallback(
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable react/no-array-index-key */
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { Badge, Box, Button, Chip, config, Icon, Icons, Menu, Spinner, Text } from 'folds';
|
||||
import { produce } from 'immer';
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable react/no-array-index-key */
|
||||
import React, { useState, MouseEventHandler, ReactNode } from 'react';
|
||||
import FocusTrap from 'focus-trap-react';
|
||||
import {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable react/destructuring-assignment */
|
||||
import React, { MouseEventHandler, useMemo } from 'react';
|
||||
import { IEventWithRoomId, JoinRule, RelationType, Room } from 'matrix-js-sdk';
|
||||
import { HTMLReactParserOptions } from 'html-react-parser';
|
||||
|
||||
@@ -556,7 +556,6 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
|
||||
.reverse()
|
||||
.map((fileItem, index) => (
|
||||
<UploadCardRenderer
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
key={index}
|
||||
isEncrypted={!!fileItem.encInfo}
|
||||
fileItem={fileItem}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable react/destructuring-assignment */
|
||||
import React, {
|
||||
Dispatch,
|
||||
MouseEventHandler,
|
||||
@@ -557,6 +556,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
|
||||
base += len;
|
||||
return seg;
|
||||
});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps -- eventsLength detects in-place timeline mutations
|
||||
}, [timeline.linkedTimelines, eventsLength]);
|
||||
const liveTimelineLinked =
|
||||
timeline.linkedTimelines[timeline.linkedTimelines.length - 1] === getLiveTimeline(room);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable react/destructuring-assignment */
|
||||
import React, { forwardRef, MouseEventHandler, useCallback, useMemo, useRef } from 'react';
|
||||
import { MatrixEvent, Room } from 'matrix-js-sdk';
|
||||
import { RoomPinnedEventsEventContent } from 'matrix-js-sdk/lib/types';
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable import/prefer-default-export */
|
||||
import { useState } from 'react';
|
||||
|
||||
export function useForceUpdate() {
|
||||
|
||||
@@ -46,12 +46,10 @@ const fillMissingPowers = (powerLevels: IPowerLevels): IPowerLevels =>
|
||||
const keys = Object.keys(DEFAULT_POWER_LEVELS) as unknown as (keyof IPowerLevels)[];
|
||||
keys.forEach((key) => {
|
||||
if (draftPl[key] === undefined) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
draftPl[key] = DEFAULT_POWER_LEVELS[key] as any;
|
||||
}
|
||||
});
|
||||
if (draftPl.notifications && typeof draftPl.notifications.room !== 'number') {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
draftPl.notifications.room = DEFAULT_POWER_LEVELS.notifications.room;
|
||||
}
|
||||
return draftPl;
|
||||
@@ -236,23 +234,22 @@ export const applyPermissionPower = (
|
||||
if (typeof location.key === 'string') {
|
||||
const users = powerLevels.users ?? {};
|
||||
users[location.key] = power;
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
|
||||
powerLevels.users = users;
|
||||
return powerLevels;
|
||||
}
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
|
||||
powerLevels.users_default = power;
|
||||
return powerLevels;
|
||||
}
|
||||
if ('action' in location) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
powerLevels[location.key] = power;
|
||||
return powerLevels;
|
||||
}
|
||||
if ('notification' in location) {
|
||||
const notifications = powerLevels.notifications ?? {};
|
||||
notifications[location.key] = power;
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
|
||||
powerLevels.notifications = notifications;
|
||||
return powerLevels;
|
||||
}
|
||||
@@ -260,11 +257,11 @@ export const applyPermissionPower = (
|
||||
if (typeof location.key === 'string') {
|
||||
const events = powerLevels.events ?? {};
|
||||
events[location.key] = power;
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
|
||||
powerLevels.events = events;
|
||||
return powerLevels;
|
||||
}
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
|
||||
powerLevels.state_default = power;
|
||||
return powerLevels;
|
||||
}
|
||||
@@ -272,11 +269,11 @@ export const applyPermissionPower = (
|
||||
if (typeof location.key === 'string') {
|
||||
const events = powerLevels.events ?? {};
|
||||
events[location.key] = power;
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
|
||||
powerLevels.events = events;
|
||||
return powerLevels;
|
||||
}
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
|
||||
powerLevels.events_default = power;
|
||||
return powerLevels;
|
||||
};
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable no-continue */
|
||||
import { MatrixEvent, Room, RoomEvent, RoomEventHandlerMap } from 'matrix-js-sdk';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { settingsAtom } from '../state/settings';
|
||||
|
||||
@@ -121,7 +121,6 @@ function InviteNotifications() {
|
||||
}, [mx, invites, perviousInviteLen, showNotifications, notificationSound, notify, playSound]);
|
||||
|
||||
return (
|
||||
// eslint-disable-next-line jsx-a11y/media-has-caption
|
||||
<audio ref={audioRef} style={{ display: 'none' }}>
|
||||
<source src={InviteSound} type="audio/ogg" />
|
||||
</audio>
|
||||
@@ -246,7 +245,6 @@ function MessageNotifications() {
|
||||
]);
|
||||
|
||||
return (
|
||||
// eslint-disable-next-line jsx-a11y/media-has-caption
|
||||
<audio ref={audioRef} style={{ display: 'none' }}>
|
||||
<source src={NotificationSound} type="audio/ogg" />
|
||||
</audio>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable react/destructuring-assignment */
|
||||
import React, { MouseEventHandler, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import {
|
||||
Avatar,
|
||||
|
||||
@@ -143,7 +143,6 @@ export class CallControl extends EventEmitter implements CallControlState {
|
||||
const callDocument = this.iframe.contentDocument ?? this.iframe.contentWindow?.document;
|
||||
if (callDocument) {
|
||||
callDocument.querySelectorAll('audio').forEach((el) => {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
el.muted = !sound;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -162,10 +162,9 @@ export class CallWidgetDriver extends WidgetDriver {
|
||||
// attempt to re-batch these up into a single request
|
||||
const invertedContentMap: { [content: string]: { userId: string; deviceId: string }[] } = {};
|
||||
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const userId of Object.keys(contentMap)) {
|
||||
const userContentMap = contentMap[userId];
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
|
||||
for (const deviceId of Object.keys(userContentMap)) {
|
||||
const content = userContentMap[deviceId];
|
||||
const stringifiedContent = JSON.stringify(content);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable jsx-a11y/alt-text */
|
||||
import React, {
|
||||
type JSX,
|
||||
ComponentPropsWithoutRef,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* eslint-disable no-bitwise, no-plusplus, no-param-reassign, no-console, prefer-template, no-continue, no-restricted-syntax */
|
||||
/* eslint-disable no-bitwise, prefer-template */
|
||||
// https://github.com/matrix-org/matrix-react-sdk/blob/e78a1adb6f1af2ea425b0bae9034fb7344a4b2e8/src/utils/MegolmExportEncryption.js
|
||||
|
||||
const subtleCrypto = window.crypto.subtle || window.crypto.webkitSubtle;
|
||||
|
||||
+28
-23
@@ -78,6 +78,27 @@ function serverMatrixSdkCryptoWasm(wasmFilePath) {
|
||||
};
|
||||
}
|
||||
|
||||
const vendorChunks = (id) => {
|
||||
if (id.includes('node_modules/matrix-js-sdk')) return 'matrix-sdk';
|
||||
if (id.includes('node_modules/react-dom')) return 'react-dom';
|
||||
if (
|
||||
id.includes('node_modules/react-router-dom') ||
|
||||
id.includes('node_modules/@remix-run') ||
|
||||
id.includes('node_modules/react-router/')
|
||||
)
|
||||
return 'router';
|
||||
if (id.includes('node_modules/@tanstack')) return 'react-query';
|
||||
if (id.includes('node_modules/linkify')) return 'linkify';
|
||||
if (id.includes('node_modules/dompurify')) return 'dompurify';
|
||||
if (id.includes('node_modules/@sentry')) return 'sentry';
|
||||
if (id.includes('node_modules/i18next') || id.includes('node_modules/react-i18next'))
|
||||
return 'i18n';
|
||||
if (id.includes('node_modules/jotai')) return 'jotai';
|
||||
if (id.includes('node_modules/immer')) return 'immer';
|
||||
if (id.includes('node_modules/folds')) return 'folds';
|
||||
if (id.includes('node_modules/emojibase')) return 'emojibase';
|
||||
};
|
||||
|
||||
export default defineConfig({
|
||||
appType: 'spa',
|
||||
publicDir: false,
|
||||
@@ -139,31 +160,15 @@ export default defineConfig({
|
||||
outDir: 'dist',
|
||||
sourcemap: process.env.SENTRY_AUTH_TOKEN ? 'hidden' : false,
|
||||
copyPublicDir: false,
|
||||
rolldownOptions: { checks: { preferBuiltinFeature: false } },
|
||||
// manualChunks must be in rolldownOptions (not rollupOptions) for Vite 8 / Rolldown
|
||||
rolldownOptions: {
|
||||
checks: { preferBuiltinFeature: false },
|
||||
output: {
|
||||
manualChunks: vendorChunks,
|
||||
},
|
||||
},
|
||||
rollupOptions: {
|
||||
plugins: [inject({ Buffer: ['buffer', 'Buffer'] })],
|
||||
output: {
|
||||
manualChunks: (id) => {
|
||||
if (id.includes('node_modules/matrix-js-sdk')) return 'matrix-sdk';
|
||||
if (id.includes('node_modules/react-dom')) return 'react-dom';
|
||||
if (
|
||||
id.includes('node_modules/react-router-dom') ||
|
||||
id.includes('node_modules/@remix-run') ||
|
||||
id.includes('node_modules/react-router/')
|
||||
)
|
||||
return 'router';
|
||||
if (id.includes('node_modules/@tanstack')) return 'react-query';
|
||||
if (id.includes('node_modules/linkify')) return 'linkify';
|
||||
if (id.includes('node_modules/dompurify')) return 'dompurify';
|
||||
if (id.includes('node_modules/@sentry')) return 'sentry';
|
||||
if (id.includes('node_modules/i18next') || id.includes('node_modules/react-i18next'))
|
||||
return 'i18n';
|
||||
if (id.includes('node_modules/jotai')) return 'jotai';
|
||||
if (id.includes('node_modules/immer')) return 'immer';
|
||||
if (id.includes('node_modules/folds')) return 'folds';
|
||||
if (id.includes('node_modules/emojibase')) return 'emojibase';
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user