Merge branch 'valere/widget_rtc_transport_action' into valere/rtc/remove_well_known_fallback

This commit is contained in:
Robin
2026-08-10 14:32:44 +02:00
23 changed files with 2185 additions and 2527 deletions

View File

@@ -7,10 +7,6 @@ jobs:
vitest: vitest:
name: Run unit tests name: Run unit tests
runs-on: ubuntu-latest runs-on: ubuntu-latest
container:
# Make sure to grab the latest version of the Playwright image
# https://playwright.dev/docs/docker#pull-the-image
image: mcr.microsoft.com/playwright:v1.61.1-noble
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
@@ -26,6 +22,18 @@ jobs:
- name: Install dependencies - name: Install dependencies
# ignore-pnpmfile should never be commited. Make CI crash if it happened (`pnpmfileChecksum` is present) # ignore-pnpmfile should never be commited. Make CI crash if it happened (`pnpmfileChecksum` is present)
run: "pnpm install --frozen-lockfile --ignore-pnpmfile" run: "pnpm install --frozen-lockfile --ignore-pnpmfile"
- name: Get Playwright version
run: echo "PLAYWRIGHT_VERSION=$(pnpm list @playwright/test --depth=0 --json | jq -r '.[0].devDependencies["@playwright/test"].version')" >> $GITHUB_ENV
- name: Cache Playwright binaries
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
id: playwright-cache
with:
path: |
~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ env.PLAYWRIGHT_VERSION }}
- name: Install Playwright binaries
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: pnpm playwright install --with-deps
- name: Vitest - name: Vitest
run: "pnpm run test:coverage" run: "pnpm run test:coverage"
- name: Upload to codecov - name: Upload to codecov
@@ -52,8 +60,18 @@ jobs:
- name: Install dependencies - name: Install dependencies
# ignore-pnpmfile should never be commited. Make CI crash if it happened (`pnpmfileChecksum` is present) # ignore-pnpmfile should never be commited. Make CI crash if it happened (`pnpmfileChecksum` is present)
run: pnpm install --frozen-lockfile --ignore-pnpmfile run: pnpm install --frozen-lockfile --ignore-pnpmfile
- name: Install Playwright Browsers - name: Get Playwright version
run: pnpm exec playwright install --with-deps run: echo "PLAYWRIGHT_VERSION=$(pnpm list @playwright/test --depth=0 --json | jq -r '.[0].devDependencies["@playwright/test"].version')" >> $GITHUB_ENV
- name: Cache Playwright binaries
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
id: playwright-cache
with:
path: |
~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ env.PLAYWRIGHT_VERSION }}
- name: Install Playwright binaries
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: pnpm playwright install --with-deps
- name: Run backend components - name: Run backend components
run: | run: |
docker compose -f docker-compose-dev.yml -f docker-compose-playwright.yml pull docker compose -f docker-compose-dev.yml -f docker-compose-playwright.yml pull

View File

@@ -40,6 +40,11 @@ jobs:
- name: Fix the owner of the downloaded files - name: Fix the owner of the downloaded files
run: "sudo chown runner:docker -R locales" run: "sudo chown runner:docker -R locales"
# Localazy doesn't write file contents in the same order that i18next-cli's
# extractor uses. We re-run the extractor after downloading to fix the order.
- name: i18n
run: pnpm i18n
- name: Formatting - name: Formatting
run: pnpm format run: pnpm format
@@ -53,7 +58,7 @@ jobs:
title: Localazy Download title: Localazy Download
commit-message: Translations updates commit-message: Translations updates
labels: | labels: |
T-Task PR-Task
- name: Enable automerge - name: Enable automerge
run: gh pr merge --merge --auto "$PR_NUMBER" run: gh pr merge --merge --auto "$PR_NUMBER"

View File

@@ -47,7 +47,7 @@ services:
- ecbackend - ecbackend
livekit: livekit:
image: livekit/livekit-server:v1.10.1 image: livekit/livekit-server:v1.13.4
pull_policy: always pull_policy: always
hostname: livekit-sfu hostname: livekit-sfu
command: --dev --config /etc/livekit.yaml command: --dev --config /etc/livekit.yaml
@@ -70,7 +70,7 @@ services:
- ecbackend - ecbackend
livekit-1: livekit-1:
image: livekit/livekit-server:v1.10.1 image: livekit/livekit-server:v1.13.4
pull_policy: always pull_policy: always
hostname: livekit-sfu-1 hostname: livekit-sfu-1
command: --dev --config /etc/livekit.yaml command: --dev --config /etc/livekit.yaml

View File

@@ -13,7 +13,7 @@ services:
- ./backend/playwright_homeserver-othersite.yaml:/data/cfg/homeserver.yaml:Z - ./backend/playwright_homeserver-othersite.yaml:/data/cfg/homeserver.yaml:Z
element-web: element-web:
# Pin to a SHA so that upstream cannot break our tests. Renovate handles regular updates. # Pin to a SHA so that upstream cannot break our tests. Renovate handles regular updates.
image: ghcr.io/element-hq/element-web:develop@sha256:d1841828a390d96da2ee64232949db641f11766fb506ec561374819d10533b9a image: ghcr.io/element-hq/element-web:develop@sha256:a23cced80588306c66bc7cfa859c591be03ece31f25d0a6a2e1e935943a35c92
element-web-1: element-web-1:
# Pin to a SHA so that upstream cannot break our tests. Renovate handles regular updates. # Pin to a SHA so that upstream cannot break our tests. Renovate handles regular updates.
image: ghcr.io/element-hq/element-web:develop@sha256:d1841828a390d96da2ee64232949db641f11766fb506ec561374819d10533b9a image: ghcr.io/element-hq/element-web:develop@sha256:a23cced80588306c66bc7cfa859c591be03ece31f25d0a6a2e1e935943a35c92

View File

@@ -86,10 +86,11 @@ to implement
In the context of MatrixRTC, we suggest using a single hostname for backend In the context of MatrixRTC, we suggest using a single hostname for backend
communication by implementing endpoint routing within a reverse proxy setup. For communication by implementing endpoint routing within a reverse proxy setup. For
the example above, this results in: the example above, this results in:
| Service | Endpoint | Example |
| -------- | ------- | ------- | | Service | Endpoint | Example |
| --------------------------------------------------------------------------------- | -------------- | ------------------------------------ |
| [Livekit SFU](https://github.com/livekit/livekit) WebSocket signalling connection | `/livekit/sfu` | `matrix-rtc.example.com/livekit/sfu` | | [Livekit SFU](https://github.com/livekit/livekit) WebSocket signalling connection | `/livekit/sfu` | `matrix-rtc.example.com/livekit/sfu` |
| [MatrixRTC Authorization Service](https://github.com/element-hq/lk-jwt-service) | `/livekit/jwt` | `matrix-rtc.example.com/livekit/jwt` | | [MatrixRTC Authorization Service](https://github.com/element-hq/lk-jwt-service) | `/livekit/jwt` | `matrix-rtc.example.com/livekit/jwt` |
Using Nginx, you can achieve this by: Using Nginx, you can achieve this by:

View File

@@ -54,6 +54,7 @@
"@radix-ui/react-slider": "^1.1.2", "@radix-ui/react-slider": "^1.1.2",
"@radix-ui/react-visually-hidden": "^1.0.3", "@radix-ui/react-visually-hidden": "^1.0.3",
"@react-spring/web": "^10.0.0", "@react-spring/web": "^10.0.0",
"@rolldown/plugin-babel": "^0.2.3",
"@sentry/react": "^8.0.0", "@sentry/react": "^8.0.0",
"@sentry/vite-plugin": "^3.0.0", "@sentry/vite-plugin": "^3.0.0",
"@storybook/addon-docs": "^10.3.6", "@storybook/addon-docs": "^10.3.6",
@@ -80,13 +81,14 @@
"@vitejs/plugin-react": "^6.0.2", "@vitejs/plugin-react": "^6.0.2",
"@vitest/browser-playwright": "^4.1.5", "@vitest/browser-playwright": "^4.1.5",
"@vitest/coverage-v8": "^4.0.18", "@vitest/coverage-v8": "^4.0.18",
"@vitest/ui": "4.1.9", "@vitest/ui": "4.1.10",
"babel-plugin-react-compiler": "^1.0.0",
"classnames": "^2.3.1", "classnames": "^2.3.1",
"copy-to-clipboard": "^3.3.3", "copy-to-clipboard": "^3.3.3",
"eslint-plugin-element-call": "link:eslint", "eslint-plugin-element-call": "link:eslint",
"eslint-plugin-storybook": "^10.3.6", "eslint-plugin-storybook": "^10.3.6",
"fetch-mock": "11.1.5", "fetch-mock": "11.1.5",
"i18next": "^25.0.0", "i18next": "^26.0.0",
"i18next-browser-languagedetector": "^8.0.0", "i18next-browser-languagedetector": "^8.0.0",
"i18next-cli": "^1.61.0", "i18next-cli": "^1.61.0",
"jsdom": "^26.0.0", "jsdom": "^26.0.0",
@@ -99,13 +101,13 @@
"node-stdlib-browser": "^1.3.1", "node-stdlib-browser": "^1.3.1",
"normalize.css": "^8.0.1", "normalize.css": "^8.0.1",
"observable-hooks": "^4.2.3", "observable-hooks": "^4.2.3",
"oxfmt": "^0.56.0", "oxfmt": "^0.61.0",
"oxlint": "^1.70.0", "oxlint": "^1.70.0",
"oxlint-tsgolint": "^0.23.0", "oxlint-tsgolint": "^0.25.0",
"pako": "^2.0.4", "pako": "^2.0.4",
"postcss": "^8.4.41", "postcss": "^8.4.41",
"postcss-preset-env": "^10.0.0", "postcss-preset-env": "^10.0.0",
"posthog-js": "1.374.0", "posthog-js": "1.408.2",
"qrcode": "^1.5.4", "qrcode": "^1.5.4",
"react": "19", "react": "19",
"react-dom": "19", "react-dom": "19",
@@ -129,5 +131,5 @@
"vitest": "^4.1.5", "vitest": "^4.1.5",
"vitest-axe": "^1.0.0-pre.3" "vitest-axe": "^1.0.0-pre.3"
}, },
"packageManager": "pnpm@11.6.0+sha512.9a36518224080c6fe5165afdcfe79bfa118c29be703f3f462b1e32efe1e98e47e8750b148e08286250aad4113cc7993ca413c4e2cd447752708c2ee5751bc95f" "packageManager": "pnpm@11.21.0+sha512.521705bce689924eac72f5a3587122f362689ef6571e55ba80076fd637c11132ecffada26fad4ea79c485bfddbfd3d5a2a5b05805a77e893de71ec8a6cca3bb1"
} }

View File

@@ -36,6 +36,7 @@ widgetTest("Footer interaction in PiP", async ({ addUser, browserName }) => {
await valere.page.waitForTimeout(600); await valere.page.waitForTimeout(600);
// Switch to the other room, the call should go to PIP // Switch to the other room, the call should go to PIP
await TestHelpers.expandRoomList(valere.page);
await TestHelpers.switchToRoomNamed(valere.page, "OtherRoom"); await TestHelpers.switchToRoomNamed(valere.page, "OtherRoom");
// We should see the PIP overlay // We should see the PIP overlay

View File

@@ -53,6 +53,7 @@ widgetTest("Put call in PIP", async ({ addUser, browserName }) => {
}); });
// Switch to the other room, the call should go to PIP // Switch to the other room, the call should go to PIP
await TestHelpers.expandRoomList(valere.page);
await TestHelpers.switchToRoomNamed(valere.page, "DoubleTask"); await TestHelpers.switchToRoomNamed(valere.page, "DoubleTask");
// We should see the PIP overlay // We should see the PIP overlay

View File

@@ -346,6 +346,12 @@ export class TestHelpers {
} }
} }
public static async expandRoomList(page: Page): Promise<void> {
await page
.getByRole("separator", { name: "Click or drag to expand" })
.click();
}
/** /**
* Switches to a room in the room list by its name. * Switches to a room in the room list by its name.
* @param page - The EW page * @param page - The EW page

4538
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -9,7 +9,7 @@ allowBuilds:
"@swc/core": true "@swc/core": true
"core-js": true "core-js": true
"esbuild": true "esbuild": true
"matrix-js-sdk@https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/8c95727b6278fe7942c20d0b9485f984dd0694b7": true "matrix-js-sdk@git+https://github.com/matrix-org/matrix-js-sdk.git": true
"protobufjs": true "protobufjs": true
overrides: overrides:
# We need compatible versions of RxJS in our dependencies and LiveKit's dependencies, but # We need compatible versions of RxJS in our dependencies and LiveKit's dependencies, but

View File

@@ -16,12 +16,15 @@ import {
HeaderStyle, HeaderStyle,
getUrlParams, getUrlParams,
} from "../src/UrlParams"; } from "../src/UrlParams";
import { mockConfig } from "./utils/test";
const ROOM_NAME = "roomNameHere"; const ROOM_NAME = "roomNameHere";
const ROOM_ID = "!d45f138fsd"; const ROOM_ID = "!d45f138fsd";
const ORIGIN = "https://call.element.io"; const ORIGIN = "https://call.element.io";
const HOMESERVER = "localhost"; const HOMESERVER = "localhost";
mockConfig();
describe("UrlParams", () => { describe("UrlParams", () => {
describe("handles URL with /room/", () => { describe("handles URL with /room/", () => {
it("and nothing else", () => { it("and nothing else", () => {

View File

@@ -183,12 +183,6 @@ export interface ConfigOptions {
// Overrides members from ConfigOptions that are always provided by the // Overrides members from ConfigOptions that are always provided by the
// default config and are therefore non-optional. // default config and are therefore non-optional.
export interface ResolvedConfigOptions extends ConfigOptions { export interface ResolvedConfigOptions extends ConfigOptions {
default_server_config: {
["m.homeserver"]: {
base_url: string;
server_name: string;
};
};
sync_disconnect_grace_period_ms: number; sync_disconnect_grace_period_ms: number;
ssla: string; ssla: string;
matrix_rtc_session: { matrix_rtc_session: {
@@ -202,12 +196,6 @@ export interface ResolvedConfigOptions extends ConfigOptions {
} }
export const DEFAULT_CONFIG: ResolvedConfigOptions = { export const DEFAULT_CONFIG: ResolvedConfigOptions = {
default_server_config: {
["m.homeserver"]: {
base_url: "http://localhost:8008",
server_name: "localhost",
},
},
features: { features: {
feature_use_device_session_member_events: true, feature_use_device_session_member_events: true,
}, },

View File

@@ -15,8 +15,7 @@ Please see LICENSE in the repository root for full details.
@import url("@fontsource/inconsolata/700.css"); @import url("@fontsource/inconsolata/700.css");
@import url("normalize.css/normalize.css") layer(normalize); @import url("normalize.css/normalize.css") layer(normalize);
@import url("@vector-im/compound-design-tokens/assets/web/css/compound-design-tokens.css") @import url("@vector-im/compound-design-tokens/assets/web/css/compound-design-tokens.css") layer(compound);
layer(compound);
@import url("@vector-im/compound-web/dist/style.css") layer(compound.components); @import url("@vector-im/compound-web/dist/style.css") layer(compound.components);
:root { :root {

View File

@@ -99,7 +99,7 @@ function renderTestComponent(
), ),
} as unknown as Room; } as unknown as Room;
if (explicitTracks?.length ?? 0 > 0) { if ((explicitTracks?.length ?? 0) > 0) {
tracks = explicitTracks!.map(({ participantId, source, kind }) => { tracks = explicitTracks!.map(({ participantId, source, kind }) => {
const participant = const participant =
liveKitParticipants.find((p) => p.identity === participantId) ?? liveKitParticipants.find((p) => p.identity === participantId) ??

View File

@@ -421,42 +421,6 @@ describe("LocalTransport", () => {
}); });
}); });
it("Should not call _unstable_getRTCTransports in widget mode but use well-known", async () => {
mockConfig({
livekit: { livekit_service_url: "https://do-not-use.lk.example.org" },
});
localTransportOpts.client.getDomain.mockReturnValue("example.org");
fetchMock.getOnce("https://example.org/.well-known/matrix/client", {
"org.matrix.msc4143.rtc_foci": [
{
type: "livekit",
livekit_service_url: "https://use-me.jwt.call.example.org",
},
],
});
localTransportOpts.client.getAccessToken.mockReturnValue(null);
const { advertised$, active$ } =
createLocalTransport$(localTransportOpts);
openIdResolver.resolve?.(openIdResponse);
expect(advertised$.value).toBe(null);
expect(active$.value).toBe(null);
await flushPromises();
expect(
localTransportOpts.client._unstable_getRTCTransports,
).not.toHaveBeenCalled();
const expectedTransport = {
type: "livekit",
livekit_service_url: "https://use-me.jwt.call.example.org",
};
expect(advertised$.value).toStrictEqual(expectedTransport);
});
it("fails fast if the openID request fails for backend config", async () => { it("fails fast if the openID request fails for backend config", async () => {
localTransportOpts.client._unstable_getRTCTransports.mockResolvedValue([ localTransportOpts.client._unstable_getRTCTransports.mockResolvedValue([
{ type: "livekit", livekit_service_url: "https://lk.example.org" }, { type: "livekit", livekit_service_url: "https://lk.example.org" },

View File

@@ -81,14 +81,12 @@ describe("RtcTransportAutoDiscovery", () => {
logger: rootLogger, logger: rootLogger,
}); });
const discoveredTransport = await discovery.discoverPreferredTransport();
const discoveredTransport = await discovery.discoverPreferredTransport();
expect(discoveredTransport).toStrictEqual(backendTransport); expect(discoveredTransport).toStrictEqual(backendTransport);
expect(discoveredTransport).not.toStrictEqual(configTransport); expect(discoveredTransport).not.toStrictEqual(configTransport);
expect(client._unstable_getRTCTransports).toHaveBeenCalledTimes(1); expect(client._unstable_getRTCTransports).toHaveBeenCalledTimes(1);
}, },
); );
@@ -107,7 +105,6 @@ describe("RtcTransportAutoDiscovery", () => {
) )
.mockResolvedValue([backendTransport]); .mockResolvedValue([backendTransport]);
const discovery = new RtcTransportAutoDiscovery({ const discovery = new RtcTransportAutoDiscovery({
client, client,
resolvedConfig: makeResolvedConfig("https://config.example.org"), resolvedConfig: makeResolvedConfig("https://config.example.org"),
@@ -140,7 +137,6 @@ describe("RtcTransportAutoDiscovery", () => {
const discoveredTransport = await discovery.discoverPreferredTransport(); const discoveredTransport = await discovery.discoverPreferredTransport();
expect(discoveredTransport).not.toStrictEqual(backendTransport); expect(discoveredTransport).not.toStrictEqual(backendTransport);
expect(discoveredTransport).toStrictEqual(configTransport); expect(discoveredTransport).toStrictEqual(configTransport);
}, },
); );
@@ -148,7 +144,6 @@ describe("RtcTransportAutoDiscovery", () => {
const client = makeClient(); const client = makeClient();
client._unstable_getRTCTransports.mockResolvedValue([]); client._unstable_getRTCTransports.mockResolvedValue([]);
const discovery = new RtcTransportAutoDiscovery({ const discovery = new RtcTransportAutoDiscovery({
client, client,
resolvedConfig: makeResolvedConfig(undefined), resolvedConfig: makeResolvedConfig(undefined),

View File

@@ -73,7 +73,7 @@ export class RtcTransportAutoDiscovery {
this.logger.info("First try to use getRTCTransports end point ..."); this.logger.info("First try to use getRTCTransports end point ...");
try { try {
const transportList = await doNetworkOperationWithRetry(async () => const transportList = await doNetworkOperationWithRetry(async () =>
client._unstable_getRTCTransports() client._unstable_getRTCTransports(),
); );
const first = transportList.find(isLivekitTransportConfig); const first = transportList.find(isLivekitTransportConfig);
if (first) { if (first) {
@@ -81,7 +81,7 @@ export class RtcTransportAutoDiscovery {
} else { } else {
this.logger.info( this.logger.info(
`No livekit transport found in getRTCTransports end point`, `No livekit transport found in getRTCTransports end point`,
transportList transportList,
); );
} }
} catch (ex) { } catch (ex) {

View File

@@ -33,6 +33,9 @@ Please see LICENSE in the repository root for full details.
.media.mirror video { .media.mirror video {
transform: scaleX(-1); transform: scaleX(-1);
/* In FF if you add a transform: scale/translate/matrix filter on an element,
it'll ignore the parents' border-radius, so force back the radius to avoid UI glitch*/
border-radius: inherit;
} }
.media[data-video-fit="cover"] video { .media[data-video-fit="cover"] video {

View File

@@ -32,6 +32,7 @@ import {
global.IntersectionObserver = class MockIntersectionObserver { global.IntersectionObserver = class MockIntersectionObserver {
public observe(): void {} public observe(): void {}
public unobserve(): void {} public unobserve(): void {}
public disconnect(): void {}
} as unknown as typeof IntersectionObserver; } as unknown as typeof IntersectionObserver;
test("SpotlightTile is accessible", async () => { test("SpotlightTile is accessible", async () => {

View File

@@ -28,6 +28,10 @@ test("useTypedEventEmitterState reacts to events", async () => {
const emitter = new TestEmitter(); const emitter = new TestEmitter();
const Test: FC = () => { const Test: FC = () => {
// Disable the React Compiler to work around the following bug:
// https://github.com/react/react/issues/34901
"use no memo";
const value = useTypedEventEmitterState( const value = useTypedEventEmitterState(
emitter, emitter,
"change", "change",
@@ -51,6 +55,10 @@ test("useTypedEventEmitterState reacts to changes made by an effect mounted on t
const emitter = new TestEmitter(); const emitter = new TestEmitter();
const Test: FC = () => { const Test: FC = () => {
// Disable the React Compiler to work around the following bug:
// https://github.com/react/react/issues/34901
"use no memo";
useEffect(() => emitter.setState(2), []); useEffect(() => emitter.setState(2), []);
const value = useTypedEventEmitterState( const value = useTypedEventEmitterState(
emitter, emitter,
@@ -69,6 +77,10 @@ test("useTypedEventEmitterState reacts to changes in getState", async () => {
const emitter = new TestEmitter(); const emitter = new TestEmitter();
const Test: FC = () => { const Test: FC = () => {
// Disable the React Compiler to work around the following bug:
// https://github.com/react/react/issues/34901
"use no memo";
const [fn, setFn] = useState(() => emitter.getState); const [fn, setFn] = useState(() => emitter.getState);
const value = useTypedEventEmitterState(emitter, "change", fn); const value = useTypedEventEmitterState(emitter, "change", fn);
return ( return (

View File

@@ -439,6 +439,12 @@ export function mockConfig(
const spy = vi.spyOn(Config, "get").mockReturnValue({ const spy = vi.spyOn(Config, "get").mockReturnValue({
...DEFAULT_CONFIG, ...DEFAULT_CONFIG,
...config, ...config,
default_server_config: {
["m.homeserver"]: {
base_url: "http://localhost:8008",
server_name: "localhost",
},
},
}); });
// simulate loading the config // simulate loading the config
vi.spyOn(Config, "init").mockResolvedValue(void 0); vi.spyOn(Config, "init").mockResolvedValue(void 0);

View File

@@ -7,7 +7,7 @@ Please see LICENSE in the repository root for full details.
import { import {
loadEnv, loadEnv,
PluginOption, type PluginOption,
searchForWorkspaceRoot, searchForWorkspaceRoot,
type ConfigEnv, type ConfigEnv,
type UserConfig, type UserConfig,
@@ -19,8 +19,8 @@ import { codecovVitePlugin } from "@codecov/vite-plugin";
import { sentryVitePlugin } from "@sentry/vite-plugin"; import { sentryVitePlugin } from "@sentry/vite-plugin";
import { nodePolyfills } from "vite-plugin-node-polyfills"; import { nodePolyfills } from "vite-plugin-node-polyfills";
import wasm from "vite-plugin-wasm"; import wasm from "vite-plugin-wasm";
import babel from "@rolldown/plugin-babel";
import react from "@vitejs/plugin-react"; import react, { reactCompilerPreset } from "@vitejs/plugin-react";
import { realpathSync } from "fs"; import { realpathSync } from "fs";
import * as fs from "node:fs"; import * as fs from "node:fs";
@@ -29,6 +29,9 @@ export const vitePluginsConfig = ({
}: Pick<ConfigEnv, "mode">): UserConfig => { }: Pick<ConfigEnv, "mode">): UserConfig => {
const env = loadEnv(mode, process.cwd()); const env = loadEnv(mode, process.cwd());
const plugins: PluginOption[] = [ const plugins: PluginOption[] = [
babel({
presets: [reactCompilerPreset()],
}),
react(), react(),
wasm(), wasm(),
nodePolyfills({ nodePolyfills({