mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-08 13:00:13 +02:00
add more dynamic imports to optimize bundle
This commit is contained in:
+34
-15
@@ -1,4 +1,3 @@
|
||||
import butterchurnPresets from 'butterchurn-presets';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -25,6 +24,38 @@ import { Text } from '/@/shared/components/text/text';
|
||||
import { Textarea } from '/@/shared/components/textarea/textarea';
|
||||
import { toast } from '/@/shared/components/toast/toast';
|
||||
|
||||
type ButterchurnPresetOption = { label: string; value: string };
|
||||
|
||||
let butterchurnPresetOptionsCache: ButterchurnPresetOption[] | null = null;
|
||||
|
||||
const loadButterchurnPresetOptions = async (): Promise<ButterchurnPresetOption[]> => {
|
||||
if (butterchurnPresetOptionsCache) return butterchurnPresetOptionsCache;
|
||||
|
||||
const mod = await import('butterchurn-presets');
|
||||
const presets = (mod as any).default ?? mod;
|
||||
const presetNames = Object.keys(presets);
|
||||
|
||||
butterchurnPresetOptionsCache = presetNames.map((presetName) => ({
|
||||
label: presetName,
|
||||
value: presetName,
|
||||
}));
|
||||
|
||||
return butterchurnPresetOptionsCache;
|
||||
};
|
||||
|
||||
const useButterchurnPresetOptions = () => {
|
||||
const [options, setOptions] = useState<ButterchurnPresetOption[]>(
|
||||
butterchurnPresetOptionsCache ?? [],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (butterchurnPresetOptionsCache) return;
|
||||
void loadButterchurnPresetOptions().then(setOptions);
|
||||
}, []);
|
||||
|
||||
return options;
|
||||
};
|
||||
|
||||
const modeOptions: { label: string; value: string }[] = [
|
||||
{ label: i18n.t('visualizer.options.mode.0') as string, value: '0' },
|
||||
{ label: i18n.t('visualizer.options.mode.1') as string, value: '1' },
|
||||
@@ -2068,13 +2099,7 @@ const ButterchurnGeneralSettings = () => {
|
||||
const { t } = useTranslation();
|
||||
const { updateProperty, visualizer } = useUpdateButterchurn();
|
||||
|
||||
const presetOptions = useMemo(() => {
|
||||
const presets = butterchurnPresets;
|
||||
return Object.keys(presets).map((presetName) => ({
|
||||
label: presetName,
|
||||
value: presetName,
|
||||
}));
|
||||
}, []);
|
||||
const presetOptions = useButterchurnPresetOptions();
|
||||
|
||||
return (
|
||||
<Fieldset legend={t('visualizer.general')}>
|
||||
@@ -2124,13 +2149,7 @@ const ButterChurnCycleSettings = () => {
|
||||
const { t } = useTranslation();
|
||||
const { updateProperty, visualizer } = useUpdateButterchurn();
|
||||
|
||||
const presetOptions = useMemo(() => {
|
||||
const presets = butterchurnPresets;
|
||||
return Object.keys(presets).map((presetName) => ({
|
||||
label: presetName,
|
||||
value: presetName,
|
||||
}));
|
||||
}, []);
|
||||
const presetOptions = useButterchurnPresetOptions();
|
||||
|
||||
return (
|
||||
<Fieldset legend={t('visualizer.cyclePresets')}>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import AudioMotionAnalyzer from 'audiomotion-analyzer';
|
||||
import { createRef, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { createRef, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import styles from './visualizer.module.css';
|
||||
|
||||
@@ -15,7 +14,31 @@ const VisualizerInner = () => {
|
||||
const accent = useAccent();
|
||||
const visualizer = useSettingsStore((store) => store.visualizer);
|
||||
const opacity = useSettingsStore((store) => store.visualizer.audiomotionanalyzer.opacity);
|
||||
const [motion, setMotion] = useState<AudioMotionAnalyzer>();
|
||||
const [motion, setMotion] = useState<any>();
|
||||
const [libraryLoaded, setLibraryLoaded] = useState(false);
|
||||
const AudioMotionAnalyzerRef = useRef<any>(null);
|
||||
|
||||
useEffect(() => {
|
||||
let isMounted = true;
|
||||
|
||||
const loadLibrary = async () => {
|
||||
try {
|
||||
const module = await import('audiomotion-analyzer');
|
||||
if (isMounted) {
|
||||
AudioMotionAnalyzerRef.current = module.default;
|
||||
setLibraryLoaded(true);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to load AudioMotionAnalyzer library:', error);
|
||||
}
|
||||
};
|
||||
|
||||
loadLibrary();
|
||||
|
||||
return () => {
|
||||
isMounted = false;
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Check if a gradient name is a custom gradient
|
||||
const isCustomGradient = useCallback(
|
||||
@@ -162,7 +185,7 @@ const VisualizerInner = () => {
|
||||
);
|
||||
|
||||
const registerCustomGradients = useCallback(
|
||||
(audioMotionInstance: AudioMotionAnalyzer) => {
|
||||
(audioMotionInstance: any) => {
|
||||
if (visualizer.type !== 'audiomotionanalyzer') {
|
||||
return;
|
||||
}
|
||||
@@ -187,8 +210,11 @@ const VisualizerInner = () => {
|
||||
|
||||
useEffect(() => {
|
||||
const { context, gains } = webAudio || {};
|
||||
let audioMotion: AudioMotionAnalyzer | undefined;
|
||||
if (gains && context && canvasRef.current && !motion) {
|
||||
let audioMotion: any | undefined;
|
||||
if (gains && context && canvasRef.current && !motion && libraryLoaded) {
|
||||
const AudioMotionAnalyzer = AudioMotionAnalyzerRef.current;
|
||||
if (!AudioMotionAnalyzer) return;
|
||||
|
||||
// Reset gradients registered flag on new instance
|
||||
setGradientsRegistered(false);
|
||||
|
||||
@@ -236,6 +262,7 @@ const VisualizerInner = () => {
|
||||
options,
|
||||
isCustomGradient,
|
||||
motion,
|
||||
libraryLoaded,
|
||||
]);
|
||||
|
||||
// Re-register custom gradients when they change
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import butterchurn from 'butterchurn';
|
||||
import butterchurnPresets from 'butterchurn-presets';
|
||||
import { createRef, useEffect, useRef, useState } from 'react';
|
||||
|
||||
import styles from './visualizer.module.css';
|
||||
@@ -27,6 +25,9 @@ const VisualizerInner = () => {
|
||||
const visualizerRef = useRef<ButterchurnVisualizer | undefined>(undefined);
|
||||
const isInitializedRef = useRef(false);
|
||||
const [isVisualizerReady, setIsVisualizerReady] = useState(false);
|
||||
const [librariesLoaded, setLibrariesLoaded] = useState(false);
|
||||
const butterchurnRef = useRef<any>(null);
|
||||
const butterchurnPresetsRef = useRef<any>(null);
|
||||
const animationFrameRef = useRef<number | undefined>(undefined);
|
||||
const resizeObserverRef = useRef<ResizeObserver | undefined>(undefined);
|
||||
const cycleTimerRef = useRef<NodeJS.Timeout | undefined>(undefined);
|
||||
@@ -39,6 +40,33 @@ const VisualizerInner = () => {
|
||||
const playerStatus = usePlayerStatus();
|
||||
const isPlaying = playerStatus === PlayerStatus.PLAYING;
|
||||
|
||||
useEffect(() => {
|
||||
let isMounted = true;
|
||||
|
||||
const loadLibraries = async () => {
|
||||
try {
|
||||
const [butterchurnModule, presetsModule] = await Promise.all([
|
||||
import('butterchurn'),
|
||||
import('butterchurn-presets'),
|
||||
]);
|
||||
|
||||
if (isMounted) {
|
||||
butterchurnRef.current = butterchurnModule.default;
|
||||
butterchurnPresetsRef.current = presetsModule.default;
|
||||
setLibrariesLoaded(true);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to load butterchurn libraries:', error);
|
||||
}
|
||||
};
|
||||
|
||||
loadLibraries();
|
||||
|
||||
return () => {
|
||||
isMounted = false;
|
||||
};
|
||||
}, []);
|
||||
|
||||
const cleanupVisualizer = () => {
|
||||
if (animationFrameRef.current) {
|
||||
cancelAnimationFrame(animationFrameRef.current);
|
||||
@@ -79,6 +107,7 @@ const VisualizerInner = () => {
|
||||
canvas &&
|
||||
container &&
|
||||
isPlaying &&
|
||||
librariesLoaded &&
|
||||
(!isInitializedRef.current || !visualizerRef.current);
|
||||
|
||||
if (!needsInitialization) {
|
||||
@@ -107,13 +136,16 @@ const VisualizerInner = () => {
|
||||
initializeVisualizer(dimensions.width, dimensions.height);
|
||||
}
|
||||
|
||||
function initializeVisualizer(width: number, height: number) {
|
||||
if (!gains || gains.length === 0 || !canvas || !context) return;
|
||||
async function initializeVisualizer(width: number, height: number) {
|
||||
if (!gains || gains.length === 0 || !canvas || !context || !librariesLoaded) return;
|
||||
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
|
||||
try {
|
||||
const butterchurn = butterchurnRef.current;
|
||||
if (!butterchurn) return;
|
||||
|
||||
const butterchurnInstance = butterchurn.createVisualizer(context, canvas, {
|
||||
height,
|
||||
width,
|
||||
@@ -138,7 +170,7 @@ const VisualizerInner = () => {
|
||||
cleanupVisualizer();
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [webAudio, isPlaying]);
|
||||
}, [webAudio, isPlaying, librariesLoaded]);
|
||||
|
||||
// Kill visualizer after 5 seconds of pause
|
||||
useEffect(() => {
|
||||
@@ -204,9 +236,11 @@ const VisualizerInner = () => {
|
||||
// Load initial preset when visualizer is ready
|
||||
useEffect(() => {
|
||||
const visualizer = visualizerRef.current;
|
||||
if (!visualizer || !isVisualizerReady || initialPresetLoadedRef.current) return;
|
||||
if (!visualizer || !isVisualizerReady || initialPresetLoadedRef.current || !librariesLoaded)
|
||||
return;
|
||||
|
||||
const presets = butterchurnPresets;
|
||||
const presets = butterchurnPresetsRef.current;
|
||||
if (!presets) return;
|
||||
const presetNames = Object.keys(presets);
|
||||
|
||||
if (presetNames.length > 0) {
|
||||
@@ -222,14 +256,24 @@ const VisualizerInner = () => {
|
||||
initialPresetLoadedRef.current = true;
|
||||
}
|
||||
}
|
||||
}, [isVisualizerReady, butterchurnSettings.currentPreset, butterchurnSettings.blendTime]);
|
||||
}, [
|
||||
isVisualizerReady,
|
||||
butterchurnSettings.currentPreset,
|
||||
butterchurnSettings.blendTime,
|
||||
librariesLoaded,
|
||||
]);
|
||||
|
||||
// Update preset when currentPreset or blendTime changes (but not when cycling)
|
||||
const isCyclingRef = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
const visualizer = visualizerRef.current;
|
||||
if (!visualizer || !butterchurnSettings.currentPreset || !initialPresetLoadedRef.current)
|
||||
if (
|
||||
!visualizer ||
|
||||
!butterchurnSettings.currentPreset ||
|
||||
!initialPresetLoadedRef.current ||
|
||||
!librariesLoaded
|
||||
)
|
||||
return;
|
||||
|
||||
// Skip if we're currently cycling (to avoid reloading preset)
|
||||
@@ -238,7 +282,8 @@ const VisualizerInner = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
const presets = butterchurnPresets;
|
||||
const presets = butterchurnPresetsRef.current;
|
||||
if (!presets) return;
|
||||
const preset = presets[butterchurnSettings.currentPreset];
|
||||
|
||||
if (preset) {
|
||||
@@ -246,12 +291,17 @@ const VisualizerInner = () => {
|
||||
// Reset cycle timer when preset changes manually
|
||||
cycleStartTimeRef.current = Date.now();
|
||||
}
|
||||
}, [butterchurnSettings.currentPreset, butterchurnSettings.blendTime]);
|
||||
}, [butterchurnSettings.currentPreset, butterchurnSettings.blendTime, librariesLoaded]);
|
||||
|
||||
// Handle preset cycling
|
||||
useEffect(() => {
|
||||
const visualizer = visualizerRef.current;
|
||||
if (!visualizer || !butterchurnSettings.cyclePresets || !initialPresetLoadedRef.current) {
|
||||
if (
|
||||
!visualizer ||
|
||||
!butterchurnSettings.cyclePresets ||
|
||||
!initialPresetLoadedRef.current ||
|
||||
!librariesLoaded
|
||||
) {
|
||||
// Clear cycle timer if cycling is disabled or visualizer not ready
|
||||
if (cycleTimerRef.current) {
|
||||
clearInterval(cycleTimerRef.current);
|
||||
@@ -260,7 +310,8 @@ const VisualizerInner = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
const presets = butterchurnPresets;
|
||||
const presets = butterchurnPresetsRef.current;
|
||||
if (!presets) return;
|
||||
const allPresetNames = Object.keys(presets);
|
||||
|
||||
// Get the list of presets to cycle through
|
||||
@@ -359,6 +410,7 @@ const VisualizerInner = () => {
|
||||
butterchurnSettings.randomizeNextPreset,
|
||||
butterchurnSettings.currentPreset,
|
||||
setSettings,
|
||||
librariesLoaded,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
Reference in New Issue
Block a user