From a8d668aa8212ef564b185e62583f629c6fe16855 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=20=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B9=20?= =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=B8=D1=87?= Date: Wed, 24 Dec 2025 03:13:26 +0300 Subject: [PATCH 1/4] feat(gallery): add dinamic import hls.js --- .changeset/eighty-masks-switch.md | 8 ++ .changeset/honest-flies-jam.md | 9 -- .../components/image-viewer/video/hls.d.ts | 6 + .../components/image-viewer/video/index.tsx | 104 ++++++++++++++---- 4 files changed, 94 insertions(+), 33 deletions(-) create mode 100644 .changeset/eighty-masks-switch.md delete mode 100644 .changeset/honest-flies-jam.md create mode 100644 packages/gallery/src/components/image-viewer/video/hls.d.ts diff --git a/.changeset/eighty-masks-switch.md b/.changeset/eighty-masks-switch.md new file mode 100644 index 0000000000..ce23670f65 --- /dev/null +++ b/.changeset/eighty-masks-switch.md @@ -0,0 +1,8 @@ +--- +'@alfalab/core-components-gallery': patch +--- + +##### Video + +- Заменен статический импорт hls.js на динамический. +- Добавлена retry логика для надежной загрузки. diff --git a/.changeset/honest-flies-jam.md b/.changeset/honest-flies-jam.md deleted file mode 100644 index a518ad0205..0000000000 --- a/.changeset/honest-flies-jam.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@alfalab/core-components-confirmation': minor -'@alfalab/core-components': minor ---- - -##### BaseConfirmation - -- Добавлен проп `maxWidth` для управления максимальной шириной контейнера. -- В `ConfirmationMobile` дефолтный `maxWidth` — `288px` (если проп не передан); для desktop дефолтного значения нет. diff --git a/packages/gallery/src/components/image-viewer/video/hls.d.ts b/packages/gallery/src/components/image-viewer/video/hls.d.ts new file mode 100644 index 0000000000..8509f9b063 --- /dev/null +++ b/packages/gallery/src/components/image-viewer/video/hls.d.ts @@ -0,0 +1,6 @@ +declare module 'hls.js/dist/hls.light.mjs' { + import Hls, { type ErrorData, type Events } from 'hls.js'; + + export default Hls; + export type { ErrorData, Events }; +} diff --git a/packages/gallery/src/components/image-viewer/video/index.tsx b/packages/gallery/src/components/image-viewer/video/index.tsx index 4b806fb9c3..fcda69214b 100644 --- a/packages/gallery/src/components/image-viewer/video/index.tsx +++ b/packages/gallery/src/components/image-viewer/video/index.tsx @@ -5,9 +5,10 @@ import React, { useContext, useEffect, useRef, + useState, } from 'react'; import cn from 'classnames'; -import Hls from 'hls.js'; +import type Hls from 'hls.js'; import { Circle } from '@alfalab/core-components-icon-view/circle'; import PlayCompactMIcon from '@alfalab/icons-glyph/PlayCompactMIcon'; @@ -28,6 +29,7 @@ type Props = { export const Video = ({ url, index, className, isActive }: Props) => { const playerRef = useRef(null); const timer = useRef>(); + const [hlsSupported, setHlsSupported] = useState(true); const { setImageMeta, @@ -49,32 +51,86 @@ export const Video = ({ url, index, className, isActive }: Props) => { /* eslint-disable-next-line react-hooks/exhaustive-deps */ }, [index]); + const loadHlsLibrary = useCallback( + async (attempt = 1, maxAttempts = 3): Promise => { + try { + const { default: HlsLib } = await import( + /* webpackChunkName: "hls-js-gallery" */ 'hls.js/dist/hls.light.mjs' + ); + + return HlsLib; + } catch { + if (attempt < maxAttempts) { + /* Экспоненциальная задержка ретрая: 300ms, 600ms, 1200ms */ + await new Promise((resolve) => { + setTimeout( + () => { + resolve(); + }, + 300 * 2 ** (attempt - 1), + ); + }); + + return loadHlsLibrary(attempt + 1, maxAttempts); + } + + setHlsSupported(false); + setImageMeta({ player: { current: null }, broken: true }, index); + + return null; + } + }, + [setImageMeta, index], + ); + useEffect(() => { - const hls = new Hls(); - - if (Hls.isSupported()) { - hls.on(Hls.Events.ERROR, (_, data) => { - if (data.fatal) { - switch (data.type) { - case Hls.ErrorTypes.MEDIA_ERROR: - hls.recoverMediaError(); - break; - case Hls.ErrorTypes.NETWORK_ERROR: - setImageMeta({ player: { current: null }, broken: true }, index); - break; - default: - hls.destroy(); - break; - } + let hls: Hls | null = null; + + const initHls = async () => { + try { + const HlsLib = await loadHlsLibrary(); + + if (!HlsLib || !playerRef.current) { + return; } - }); - hls.loadSource(url); - if (playerRef.current) { - hls.attachMedia(playerRef.current); - hls.subtitleDisplay = false; + if (!HlsLib.isSupported()) { + setHlsSupported(false); + + return; + } + + hls = new HlsLib(); + + hls.on(HlsLib.Events.ERROR, (_, data) => { + if (data.fatal && hls) { + switch (data.type) { + case HlsLib.ErrorTypes.MEDIA_ERROR: + hls.recoverMediaError(); + break; + case HlsLib.ErrorTypes.NETWORK_ERROR: + setImageMeta({ player: { current: null }, broken: true }, index); + break; + default: + hls.destroy(); + break; + } + } + }); + + hls.loadSource(url); + + if (playerRef.current) { + hls.attachMedia(playerRef.current); + hls.subtitleDisplay = false; + } + } catch { + setHlsSupported(false); + setImageMeta({ player: { current: null }, broken: true }, index); } - } + }; + + initHls(); return () => { if (hls) { @@ -183,7 +239,7 @@ export const Video = ({ url, index, className, isActive }: Props) => { playsInline={true} muted={mutedVideo} loop={true} - src={Hls.isSupported() ? undefined : url} + src={hlsSupported ? undefined : url} className={cn(styles.video, { [styles.mobile]: view === 'mobile' }, className)} > From f117225b7af3a037db333b0782a4e284efe3f88b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=20=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B9=20?= =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=B8=D1=87?= Date: Mon, 29 Dec 2025 13:07:00 +0300 Subject: [PATCH 2/4] feat(gallery): revert full version lib --- packages/gallery/src/components/image-viewer/video/hls.d.ts | 6 ------ .../gallery/src/components/image-viewer/video/index.tsx | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) delete mode 100644 packages/gallery/src/components/image-viewer/video/hls.d.ts diff --git a/packages/gallery/src/components/image-viewer/video/hls.d.ts b/packages/gallery/src/components/image-viewer/video/hls.d.ts deleted file mode 100644 index 8509f9b063..0000000000 --- a/packages/gallery/src/components/image-viewer/video/hls.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module 'hls.js/dist/hls.light.mjs' { - import Hls, { type ErrorData, type Events } from 'hls.js'; - - export default Hls; - export type { ErrorData, Events }; -} diff --git a/packages/gallery/src/components/image-viewer/video/index.tsx b/packages/gallery/src/components/image-viewer/video/index.tsx index fcda69214b..9899319201 100644 --- a/packages/gallery/src/components/image-viewer/video/index.tsx +++ b/packages/gallery/src/components/image-viewer/video/index.tsx @@ -55,7 +55,7 @@ export const Video = ({ url, index, className, isActive }: Props) => { async (attempt = 1, maxAttempts = 3): Promise => { try { const { default: HlsLib } = await import( - /* webpackChunkName: "hls-js-gallery" */ 'hls.js/dist/hls.light.mjs' + /* webpackChunkName: "hls-js-gallery" */ 'hls.js' ); return HlsLib; From 7469566122b9e87e909c5258df5a44836bcb6ceb Mon Sep 17 00:00:00 2001 From: Aleksey <77746016+AlekseyLexey@users.noreply.github.com> Date: Tue, 3 Feb 2026 14:54:59 +0300 Subject: [PATCH 3/4] Update .changeset/eighty-masks-switch.md Co-authored-by: fulcanellee <45999900+fulcanellee@users.noreply.github.com> --- .changeset/eighty-masks-switch.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/eighty-masks-switch.md b/.changeset/eighty-masks-switch.md index ce23670f65..617f4c0b0b 100644 --- a/.changeset/eighty-masks-switch.md +++ b/.changeset/eighty-masks-switch.md @@ -2,7 +2,7 @@ '@alfalab/core-components-gallery': patch --- -##### Video +##### Gallery - Заменен статический импорт hls.js на динамический. - Добавлена retry логика для надежной загрузки. From 4b42badf905ca9490563c99a92807109f29fa4d4 Mon Sep 17 00:00:00 2001 From: Aleksey <77746016+AlekseyLexey@users.noreply.github.com> Date: Tue, 3 Feb 2026 14:55:34 +0300 Subject: [PATCH 4/4] Update .changeset/eighty-masks-switch.md Co-authored-by: fulcanellee <45999900+fulcanellee@users.noreply.github.com> --- .changeset/eighty-masks-switch.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.changeset/eighty-masks-switch.md b/.changeset/eighty-masks-switch.md index 617f4c0b0b..0512624c7b 100644 --- a/.changeset/eighty-masks-switch.md +++ b/.changeset/eighty-masks-switch.md @@ -1,4 +1,5 @@ --- +'@alfalab/core-components': patch '@alfalab/core-components-gallery': patch ---