hookehuyr

perf: 优化代码分割与懒加载以提升应用性能

- 将 PdfViewer 和 VideoPlayer 组件改为异步加载,减少初始包体积
- 为视频播放器相关依赖添加动态导入,避免未使用时加载
- 在打包配置中添加手动分包策略,将 vue-office 和图像工具库分离为独立 chunk
- 优化 Safari 浏览器检测逻辑,避免直接导入 video.js 以支持懒加载
...@@ -116,8 +116,9 @@ ...@@ -116,8 +116,9 @@
116 </template> 116 </template>
117 117
118 <script setup> 118 <script setup>
119 -import { ref, watch, nextTick, onUnmounted } from 'vue'; 119 +import { defineAsyncComponent, ref, watch, nextTick, onUnmounted } from 'vue';
120 -import PDF from "pdf-vue3"; 120 +
121 +const PDF = defineAsyncComponent(() => import("pdf-vue3"));
121 122
122 /** 123 /**
123 * 组件属性定义 124 * 组件属性定义
......
...@@ -62,11 +62,18 @@ ...@@ -62,11 +62,18 @@
62 </template> 62 </template>
63 63
64 <script setup> 64 <script setup>
65 -import { ref } from "vue"; 65 +import { defineAsyncComponent, ref } from "vue";
66 -import { VideoPlayer } from "@videojs-player/vue";
67 -import "video.js/dist/video-js.css";
68 import { useVideoPlayer } from "@/composables/useVideoPlayer"; 66 import { useVideoPlayer } from "@/composables/useVideoPlayer";
69 67
68 +const VideoPlayer = defineAsyncComponent(async () => {
69 + await import("video.js/dist/video-js.css");
70 + await import("videojs-hls-quality-selector/dist/videojs-hls-quality-selector.css");
71 + await import("videojs-contrib-quality-levels");
72 + await import("videojs-hls-quality-selector");
73 + const mod = await import("@videojs-player/vue");
74 + return mod.VideoPlayer;
75 +});
76 +
70 const props = defineProps({ 77 const props = defineProps({
71 options: { 78 options: {
72 type: Object, 79 type: Object,
......
1 import { ref, computed, watch, onMounted, onBeforeUnmount } from 'vue'; 1 import { ref, computed, watch, onMounted, onBeforeUnmount } from 'vue';
2 import { wxInfo } from "@/utils/tools"; 2 import { wxInfo } from "@/utils/tools";
3 -import videojs from "video.js";
4 import { buildVideoSources, canPlayHlsNatively } from "./videoPlayerSource"; 3 import { buildVideoSources, canPlayHlsNatively } from "./videoPlayerSource";
5 import { useVideoProbe } from "./useVideoProbe"; 4 import { useVideoProbe } from "./useVideoProbe";
6 import { useVideoPlaybackOverlays } from "./useVideoPlaybackOverlays"; 5 import { useVideoPlaybackOverlays } from "./useVideoPlaybackOverlays";
7 -// 新增:引入多码率切换插件 6 +
8 -import 'videojs-contrib-quality-levels'; // 用于读取 m3u8 中的多码率信息 7 +const is_safari_browser = () => {
9 -import 'videojs-hls-quality-selector'; // 用于在播放器控制条显示“清晰度”切换菜单(支持 Auto/720p/480p 等)。 8 + if (typeof navigator === 'undefined') return false;
10 -import 'videojs-hls-quality-selector/dist/videojs-hls-quality-selector.css'; 9 + const ua = navigator.userAgent || '';
10 + const is_safari = /safari/i.test(ua) && !/chrome|crios|android|fxios|edg/i.test(ua);
11 + return is_safari;
12 +};
11 13
12 /** 14 /**
13 * - 使用方法 :您无需修改业务代码。只要传入的视频 URL 是七牛云生成的多码率 .m3u8 地址,播放器控制条右下角会自动出现“齿轮”图标,用户点击即可切换清晰度(或选择 Auto 自动切换)。 15 * - 使用方法 :您无需修改业务代码。只要传入的视频 URL 是七牛云生成的多码率 .m3u8 地址,播放器控制条右下角会自动出现“齿轮”图标,用户点击即可切换清晰度(或选择 Auto 自动切换)。
...@@ -271,7 +273,7 @@ export function useVideoPlayer(props, emit, videoRef, nativeVideoRef) { ...@@ -271,7 +273,7 @@ export function useVideoPlayer(props, emit, videoRef, nativeVideoRef) {
271 // 5. Video.js 播放器逻辑 (PC/Android) 273 // 5. Video.js 播放器逻辑 (PC/Android)
272 const shouldOverrideNativeHls = computed(() => { 274 const shouldOverrideNativeHls = computed(() => {
273 if (!isM3U8.value) return false; 275 if (!isM3U8.value) return false;
274 - if (videojs.browser.IS_SAFARI) return false; 276 + if (is_safari_browser()) return false;
275 // 非 Safari 且不具备原生 HLS 时,强制 video.js 的 VHS 来解 m3u8 277 // 非 Safari 且不具备原生 HLS 时,强制 video.js 的 VHS 来解 m3u8
276 return !canPlayHlsNatively(); 278 return !canPlayHlsNatively();
277 }); 279 });
......
1 <!-- 1 <!--
2 * @Date: 2025-10-22 10:45:51 2 * @Date: 2025-10-22 10:45:51
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2025-10-22 10:54:10 4 + * @LastEditTime: 2026-01-24 14:00:37
5 * @FilePath: /mlaj/src/views/study/PdfPreviewPage.vue 5 * @FilePath: /mlaj/src/views/study/PdfPreviewPage.vue
6 - * @Description: 文件描述 6 + * @Description: PDF预览页
7 --> 7 -->
8 <template> 8 <template>
9 <div class="pdf-preview-page"> 9 <div class="pdf-preview-page">
...@@ -12,9 +12,10 @@ ...@@ -12,9 +12,10 @@
12 </template> 12 </template>
13 13
14 <script setup> 14 <script setup>
15 -import { computed, onMounted, onBeforeUnmount } from 'vue' 15 +import { computed, defineAsyncComponent, onMounted, onBeforeUnmount } from 'vue'
16 import { useRoute, useRouter } from 'vue-router' 16 import { useRoute, useRouter } from 'vue-router'
17 -import PdfViewer from '@/components/media/PdfViewer.vue' 17 +
18 +const PdfViewer = defineAsyncComponent(() => import('@/components/media/PdfViewer.vue'))
18 19
19 const route = useRoute() 20 const route = useRoute()
20 const router = useRouter() 21 const router = useRouter()
......
1 /* 1 /*
2 * @Date: 2025-03-20 19:53:12 2 * @Date: 2025-03-20 19:53:12
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2026-01-18 23:17:57 4 + * @LastEditTime: 2026-01-24 13:56:05
5 * @FilePath: /mlaj/vite.config.js 5 * @FilePath: /mlaj/vite.config.js
6 * @Description: 文件描述 6 * @Description: 文件描述
7 */ 7 */
...@@ -111,6 +111,11 @@ export default ({ mode }) => { ...@@ -111,6 +111,11 @@ export default ({ mode }) => {
111 chunkFileNames: 'static/js/[name]-[hash].js', 111 chunkFileNames: 'static/js/[name]-[hash].js',
112 entryFileNames: 'static/js/[name]-[hash].js', 112 entryFileNames: 'static/js/[name]-[hash].js',
113 assetFileNames: 'static/[ext]/[name]-[hash].[ext]', 113 assetFileNames: 'static/[ext]/[name]-[hash].[ext]',
114 + manualChunks: (id) => {
115 + if (!id.includes('node_modules')) return;
116 + if (id.includes('@vue-office/docx') || id.includes('@vue-office/excel') || id.includes('@vue-office/pptx')) return 'vue-office';
117 + if (id.includes('html2canvas') || id.includes('html-to-image')) return 'image-tools';
118 + },
114 }, 119 },
115 input: { // 多页面应用模式, 打包时配置,运行配置要处理root 120 input: { // 多页面应用模式, 打包时配置,运行配置要处理root
116 main: path.resolve(__dirname, 'index.html'), 121 main: path.resolve(__dirname, 'index.html'),
......