diff --git a/changes/changelog.d/front-split-large-bundles.enhancement b/changes/changelog.d/front-split-large-bundles.enhancement
new file mode 100644
index 000000000..cb53791b5
--- /dev/null
+++ b/changes/changelog.d/front-split-large-bundles.enhancement
@@ -0,0 +1 @@
+Split front large bundles into smaller chunks
diff --git a/front/src/App.vue b/front/src/App.vue
index 51bdf2a03..a323ade35 100644
--- a/front/src/App.vue
+++ b/front/src/App.vue
@@ -2,24 +2,24 @@
import type { QueueTrack } from '~/composables/audio/queue'
import { useIntervalFn, useToggle, useWindowSize } from '@vueuse/core'
-import { computed, nextTick, onMounted, ref, watchEffect } from 'vue'
+import { computed, nextTick, onMounted, ref, watchEffect, defineAsyncComponent } from 'vue'
import { useQueue } from '~/composables/audio/queue'
import { useStore } from '~/store'
-import ChannelUploadModal from '~/components/channels/UploadModal.vue'
-import PlaylistModal from '~/components/playlists/PlaylistModal.vue'
-import FilterModal from '~/components/moderation/FilterModal.vue'
-import ReportModal from '~/components/moderation/ReportModal.vue'
-import SetInstanceModal from '~/components/SetInstanceModal.vue'
-import ServiceMessages from '~/components/ServiceMessages.vue'
-import ShortcutsModal from '~/components/ShortcutsModal.vue'
-import AudioPlayer from '~/components/audio/Player.vue'
-import Sidebar from '~/components/Sidebar.vue'
-import Queue from '~/components/Queue.vue'
-
import onKeyboardShortcut from '~/composables/onKeyboardShortcut'
+const ChannelUploadModal = defineAsyncComponent(() => import('~/components/channels/UploadModal.vue'))
+const PlaylistModal = defineAsyncComponent(() => import('~/components/playlists/PlaylistModal.vue'))
+const FilterModal = defineAsyncComponent(() => import('~/components/moderation/FilterModal.vue'))
+const ReportModal = defineAsyncComponent(() => import('~/components/moderation/ReportModal.vue'))
+const SetInstanceModal = defineAsyncComponent(() => import('~/components/SetInstanceModal.vue'))
+const ServiceMessages = defineAsyncComponent(() => import('~/components/ServiceMessages.vue'))
+const ShortcutsModal = defineAsyncComponent(() => import('~/components/ShortcutsModal.vue'))
+const AudioPlayer = defineAsyncComponent(() => import('~/components/audio/Player.vue'))
+const Sidebar = defineAsyncComponent(() => import('~/components/Sidebar.vue'))
+const Queue = defineAsyncComponent(() => import('~/components/Queue.vue'))
+
const store = useStore()
// Tracks
@@ -124,7 +124,3 @@ store.dispatch('auth/fetchUser')
-
-
diff --git a/front/src/components/Queue.vue b/front/src/components/Queue.vue
index 0fa7379ec..0e21cc3e0 100644
--- a/front/src/components/Queue.vue
+++ b/front/src/components/Queue.vue
@@ -2,7 +2,7 @@
import type { QueueItemSource } from '~/types'
import { whenever, watchDebounced, useCurrentElement, useScrollLock, useFullscreen, useIdle, refAutoReset, useStorage } from '@vueuse/core'
-import { nextTick, ref, computed, watchEffect, onMounted } from 'vue'
+import { nextTick, ref, computed, watchEffect, onMounted, defineAsyncComponent } from 'vue'
import { useFocusTrap } from '@vueuse/integrations/useFocusTrap'
import { useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
@@ -17,11 +17,12 @@ import time from '~/utils/time'
import TrackFavoriteIcon from '~/components/favorites/TrackFavoriteIcon.vue'
import TrackPlaylistIcon from '~/components/playlists/TrackPlaylistIcon.vue'
import PlayerControls from '~/components/audio/PlayerControls.vue'
-import MilkDrop from '~/components/audio/visualizer/MilkDrop.vue'
import VirtualList from '~/components/vui/list/VirtualList.vue'
import QueueItem from '~/components/QueueItem.vue'
+const MilkDrop = defineAsyncComponent(() => import('~/components/audio/visualizer/MilkDrop.vue'))
+
const {
isPlaying,
currentTime,
diff --git a/front/src/main.ts b/front/src/main.ts
index d7ffdbb7d..c24863ca8 100644
--- a/front/src/main.ts
+++ b/front/src/main.ts
@@ -8,6 +8,8 @@ import { createApp, defineAsyncComponent, h } from 'vue'
import useLogger from '~/composables/useLogger'
import useTheme from '~/composables/useTheme'
+import '~/style/_main.scss'
+
import '~/api'
// NOTE: Set the theme as fast as possible
diff --git a/front/src/style/globals/_utils.scss b/front/src/style/globals/_utils.scss
index 67423876f..ccb00ce7d 100644
--- a/front/src/style/globals/_utils.scss
+++ b/front/src/style/globals/_utils.scss
@@ -107,7 +107,7 @@ span.diff.removed {
}
.default-cover {
- background-image: url("./assets/audio/default-cover.png") !important;
+ background-image: url("~/assets/audio/default-cover.png") !important;
}
.discrete {
diff --git a/front/vite.config.ts b/front/vite.config.ts
index 470917fcc..fe866ea67 100644
--- a/front/vite.config.ts
+++ b/front/vite.config.ts
@@ -54,6 +54,23 @@ export default defineConfig(({ mode }) => ({
'~': resolve(__dirname, './src')
}
},
+ build: {
+ // https://rollupjs.org/configuration-options/
+ rollupOptions: {
+ output: {
+ manualChunks: {
+ 'axios': ['axios', 'axios-auth-refresh'],
+ 'dompurify': ['dompurify'],
+ 'jquery': ['jquery'],
+ 'lodash': ['lodash-es'],
+ 'moment': ['moment'],
+ 'sentry': ['@sentry/vue', '@sentry/tracing'],
+ 'standardized-audio-context': ['standardized-audio-context'],
+ 'vue-router': ['vue-router'],
+ }
+ }
+ }
+ },
test: {
environment: 'jsdom',
globals: true,