mirror of
https://github.com/Megghy/vtsuru.live.git
synced 2025-12-06 18:36:55 +08:00
perf: optimize build chunks and add bundle size visualization
This commit is contained in:
@@ -90,8 +90,10 @@
|
|||||||
"eslint": "^9.36.0",
|
"eslint": "^9.36.0",
|
||||||
"eslint-plugin-oxlint": "^1.19.0",
|
"eslint-plugin-oxlint": "^1.19.0",
|
||||||
"oxlint": "^1.19.0",
|
"oxlint": "^1.19.0",
|
||||||
|
"rollup-plugin-visualizer": "^6.0.4",
|
||||||
"stylus": "^0.64.0",
|
"stylus": "^0.64.0",
|
||||||
"typescript": "^5.9.2",
|
"typescript": "^5.9.2",
|
||||||
|
"vite-plugin-cdn-import": "^1.0.1",
|
||||||
"vue-vine": "^1.7.6"
|
"vue-vine": "^1.7.6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { ComputedRef } from 'vue'
|
import type { ComputedRef, Ref } from 'vue'
|
||||||
import type { DanmakuWindowSettings } from '../../store/useDanmakuWindow'
|
import type { DanmakuWindowSettings } from '../../store/useDanmakuWindow'
|
||||||
import type { EventModel } from '@/api/api-models'
|
import type { EventModel } from '@/api/api-models'
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
@@ -67,7 +67,8 @@ export interface BaseDanmakuItemProps {
|
|||||||
|
|
||||||
export function useDanmakuUtils(
|
export function useDanmakuUtils(
|
||||||
props: BaseDanmakuItemProps,
|
props: BaseDanmakuItemProps,
|
||||||
emojiData: { data: { inline: { [key: string]: string }, plain: { [key: string]: string } } },
|
emojiData: Ref<{ updateAt?: number, data: { inline: { [key: string]: string }, plain: { [key: string]: string } } }>
|
||||||
|
| { data: { inline: { [key: string]: string }, plain: { [key: string]: string } } },
|
||||||
) {
|
) {
|
||||||
// 计算SC弹幕的颜色类
|
// 计算SC弹幕的颜色类
|
||||||
const scColorClass = computed(() => {
|
const scColorClass = computed(() => {
|
||||||
@@ -124,7 +125,12 @@ export function useDanmakuUtils(
|
|||||||
let match
|
let match
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const availableEmojis = emojiData.data || {} // 确保 emojiData 已加载
|
// 兼容 Ref 和 普通对象两种传参
|
||||||
|
const store = (emojiData as any)?.value ?? emojiData
|
||||||
|
const availableEmojis = (store?.data ?? { inline: {}, plain: {} }) as {
|
||||||
|
inline?: { [key: string]: string }
|
||||||
|
plain?: { [key: string]: string }
|
||||||
|
}
|
||||||
|
|
||||||
while ((match = regex.exec(props.item.msg)) !== null) {
|
while ((match = regex.exec(props.item.msg)) !== null) {
|
||||||
// 添加表情前的文本部分
|
// 添加表情前的文本部分
|
||||||
@@ -133,7 +139,12 @@ export function useDanmakuUtils(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const emojiFullName = match[0] // 完整匹配,例如 "[哈哈]"
|
const emojiFullName = match[0] // 完整匹配,例如 "[哈哈]"
|
||||||
const emojiInfo = availableEmojis.inline[emojiFullName] || availableEmojis.plain[emojiFullName]
|
const emojiName = match[1] // 去除方括号后的名称,例如 "哈哈"
|
||||||
|
// 兼容键名为带/不带方括号的两种情况
|
||||||
|
const emojiInfo = (availableEmojis.inline?.[emojiFullName]
|
||||||
|
?? availableEmojis.inline?.[emojiName]
|
||||||
|
?? availableEmojis.plain?.[emojiFullName]
|
||||||
|
?? availableEmojis.plain?.[emojiName]) as string | undefined
|
||||||
|
|
||||||
if (emojiInfo) {
|
if (emojiInfo) {
|
||||||
// 找到了表情
|
// 找到了表情
|
||||||
|
|||||||
6
src/components.d.ts
vendored
6
src/components.d.ts
vendored
@@ -22,13 +22,19 @@ declare module 'vue' {
|
|||||||
NAvatar: typeof import('naive-ui')['NAvatar']
|
NAvatar: typeof import('naive-ui')['NAvatar']
|
||||||
NButton: typeof import('naive-ui')['NButton']
|
NButton: typeof import('naive-ui')['NButton']
|
||||||
NCard: typeof import('naive-ui')['NCard']
|
NCard: typeof import('naive-ui')['NCard']
|
||||||
|
NEllipsis: typeof import('naive-ui')['NEllipsis']
|
||||||
|
NEmpty: typeof import('naive-ui')['NEmpty']
|
||||||
NFlex: typeof import('naive-ui')['NFlex']
|
NFlex: typeof import('naive-ui')['NFlex']
|
||||||
|
NFormItemGi: typeof import('naive-ui')['NFormItemGi']
|
||||||
|
NGridItem: typeof import('naive-ui')['NGridItem']
|
||||||
NIcon: typeof import('naive-ui')['NIcon']
|
NIcon: typeof import('naive-ui')['NIcon']
|
||||||
NImage: typeof import('naive-ui')['NImage']
|
NImage: typeof import('naive-ui')['NImage']
|
||||||
NPopconfirm: typeof import('naive-ui')['NPopconfirm']
|
NPopconfirm: typeof import('naive-ui')['NPopconfirm']
|
||||||
|
NScrollbar: typeof import('naive-ui')['NScrollbar']
|
||||||
NSpace: typeof import('naive-ui')['NSpace']
|
NSpace: typeof import('naive-ui')['NSpace']
|
||||||
NTag: typeof import('naive-ui')['NTag']
|
NTag: typeof import('naive-ui')['NTag']
|
||||||
NText: typeof import('naive-ui')['NText']
|
NText: typeof import('naive-ui')['NText']
|
||||||
|
NTime: typeof import('naive-ui')['NTime']
|
||||||
PointGoodsItem: typeof import('./components/manage/PointGoodsItem.vue')['default']
|
PointGoodsItem: typeof import('./components/manage/PointGoodsItem.vue')['default']
|
||||||
PointHistoryCard: typeof import('./components/manage/PointHistoryCard.vue')['default']
|
PointHistoryCard: typeof import('./components/manage/PointHistoryCard.vue')['default']
|
||||||
PointOrderCard: typeof import('./components/manage/PointOrderCard.vue')['default']
|
PointOrderCard: typeof import('./components/manage/PointOrderCard.vue')['default']
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
name: 'index',
|
name: 'index',
|
||||||
component: IndexView,
|
component: async () => import('@/views/IndexView.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
title: '你好',
|
title: '你好',
|
||||||
},
|
},
|
||||||
|
|||||||
163
vite.config.mts
163
vite.config.mts
@@ -9,6 +9,7 @@ import Markdown from 'unplugin-vue-markdown/vite'
|
|||||||
import { defineConfig } from 'vite'
|
import { defineConfig } from 'vite'
|
||||||
import svgLoader from 'vite-svg-loader'
|
import svgLoader from 'vite-svg-loader'
|
||||||
import { VineVitePlugin } from 'vue-vine/vite'
|
import { VineVitePlugin } from 'vue-vine/vite'
|
||||||
|
import { visualizer } from 'rollup-plugin-visualizer';
|
||||||
|
|
||||||
// 自定义SVGO插件,删除所有名称以sodipodi:和inkscape:开头的元素
|
// 自定义SVGO插件,删除所有名称以sodipodi:和inkscape:开头的元素
|
||||||
const removeSodipodiInkscape = {
|
const removeSodipodiInkscape = {
|
||||||
@@ -87,6 +88,14 @@ export default defineConfig({
|
|||||||
include: [/\.vue$/, /\.vue\?vue/, /\.md$/, /\.vine$/],
|
include: [/\.vue$/, /\.vue\?vue/, /\.md$/, /\.vine$/],
|
||||||
}),
|
}),
|
||||||
VineVitePlugin(),
|
VineVitePlugin(),
|
||||||
|
visualizer({
|
||||||
|
open: false, // 不自动打开浏览器,避免影响 CI/CD
|
||||||
|
gzipSize: true, // 显示 Gzip 压缩后的大小
|
||||||
|
brotliSize: true, // 显示 Brotli 压缩后的大小
|
||||||
|
filename: 'dist/stats.html', // 分析报告的输出路径
|
||||||
|
template: 'treemap', // 使用树图模式展示
|
||||||
|
sourcemap: true, // 使用 sourcemap 进行更精确的分析
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
server: { port: 51000 },
|
server: { port: 51000 },
|
||||||
resolve: { alias: { '@': path.resolve(__dirname, 'src') } },
|
resolve: { alias: { '@': path.resolve(__dirname, 'src') } },
|
||||||
@@ -96,29 +105,161 @@ export default defineConfig({
|
|||||||
'__BUILD_TIME__': JSON.stringify(new Date().toISOString()),
|
'__BUILD_TIME__': JSON.stringify(new Date().toISOString()),
|
||||||
},
|
},
|
||||||
optimizeDeps: {
|
optimizeDeps: {
|
||||||
include: ['@vicons/fluent', '@vicons/ionicons5', 'vue', 'vue-router'],
|
include: [
|
||||||
|
'vue',
|
||||||
|
'vue-router',
|
||||||
|
'pinia',
|
||||||
|
'@vueuse/core',
|
||||||
|
'naive-ui',
|
||||||
|
'date-fns',
|
||||||
|
'@vicons/fluent',
|
||||||
|
'@vicons/ionicons5',
|
||||||
|
],
|
||||||
|
exclude: ['@tauri-apps/api', '@tauri-apps/plugin-autostart', '@tauri-apps/plugin-http'],
|
||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
sourcemap: true,
|
sourcemap: true,
|
||||||
target: 'esnext',
|
target: 'esnext',
|
||||||
minify: 'oxc',
|
minify: 'oxc',
|
||||||
chunkSizeWarningLimit: 1000,
|
chunkSizeWarningLimit: 1600, // 调整警告阈值,gamepad-assets 会比较大
|
||||||
|
cssCodeSplit: true,
|
||||||
|
cssMinify: 'lightningcss',
|
||||||
|
// 报告压缩后的文件大小
|
||||||
|
reportCompressedSize: true,
|
||||||
|
// 优化模块预加载策略
|
||||||
|
modulePreload: {
|
||||||
|
polyfill: true,
|
||||||
|
},
|
||||||
|
// 静态资源内联阈值(小于此大小的资源会被内联为 base64)
|
||||||
|
assetsInlineLimit: 4096, // 4KB,默认值,可根据需要调整
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
output: { // @ts-ignore
|
output: {
|
||||||
advancedChunks: {
|
advancedChunks: {
|
||||||
groups: [
|
groups: [
|
||||||
{
|
{
|
||||||
name: 'vue-vendor',
|
name: (id: string) => {
|
||||||
test: /[\\/]node_modules[\\/](vue|vue-router|pinia)[\\/]/,
|
// 核心框架
|
||||||
priority: -10,
|
if (id.includes('node_modules/vue/') || id.includes('node_modules/@vue/')) {
|
||||||
},
|
return 'vue-core'
|
||||||
{
|
}
|
||||||
name: 'ui-vendor',
|
if (id.includes('node_modules/vue-router/')) {
|
||||||
test: /[\\/]node_modules[\\/](naive-ui|@vueuse[\\/]core)[\\/]/,
|
return 'vue-router'
|
||||||
priority: -10,
|
}
|
||||||
|
if (id.includes('node_modules/pinia/')) {
|
||||||
|
return 'pinia'
|
||||||
|
}
|
||||||
|
|
||||||
|
// UI 框架及相关
|
||||||
|
if (id.includes('node_modules/naive-ui/') || id.includes('node_modules/vueuc/')) {
|
||||||
|
return 'naive-ui'
|
||||||
|
}
|
||||||
|
|
||||||
|
// VueUse 系列
|
||||||
|
if (id.includes('node_modules/@vueuse/')) {
|
||||||
|
return 'vueuse'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 图标库
|
||||||
|
if (id.includes('node_modules/@vicons/')) {
|
||||||
|
return 'icons'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gamepad 配置和资源(体积大,单独分离)
|
||||||
|
if (id.includes('/gamepadConfigs') || id.includes('assets/controller/')) {
|
||||||
|
return 'gamepad-assets'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字典文件(拼音、假名等,按需加载)
|
||||||
|
if (id.includes('/dictPinyin')) {
|
||||||
|
return 'dict-pinyin'
|
||||||
|
}
|
||||||
|
if (id.includes('/dictKana')) {
|
||||||
|
return 'dict-kana'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Monaco Editor (代码编辑器,体积大)
|
||||||
|
if (id.includes('node_modules/monaco-editor/') || id.includes('node_modules/@guolao/vue-monaco-editor/')) {
|
||||||
|
return 'monaco-editor'
|
||||||
|
}
|
||||||
|
|
||||||
|
// ECharts (图表库,体积大)
|
||||||
|
if (id.includes('node_modules/echarts/') || id.includes('node_modules/vue-echarts/')) {
|
||||||
|
return 'echarts'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 富文本编辑器
|
||||||
|
if (id.includes('node_modules/@wangeditor/')) {
|
||||||
|
return 'wangeditor'
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignalR 相关
|
||||||
|
if (id.includes('node_modules/@microsoft/signalr')) {
|
||||||
|
return 'signalr'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tauri 相关(客户端专用)
|
||||||
|
if (id.includes('node_modules/@tauri-apps/')) {
|
||||||
|
return 'tauri'
|
||||||
|
}
|
||||||
|
|
||||||
|
// B站直播弹幕客户端
|
||||||
|
if (id.includes('node_modules/bilibili-live-danmaku/')) {
|
||||||
|
return 'bili-danmaku'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 工具库
|
||||||
|
if (id.includes('node_modules/lodash/')) {
|
||||||
|
return 'lodash'
|
||||||
|
}
|
||||||
|
if (id.includes('node_modules/date-fns/')) {
|
||||||
|
return 'date-fns'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Excel 相关 (体积大)
|
||||||
|
if (id.includes('node_modules/xlsx/')) {
|
||||||
|
return 'xlsx'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 压缩和解压
|
||||||
|
if (id.includes('node_modules/jszip/') || id.includes('node_modules/@oneidentity/zstd-js/')) {
|
||||||
|
return 'compression'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 其他大型依赖
|
||||||
|
if (id.includes('node_modules/html2canvas/')) {
|
||||||
|
return 'html2canvas'
|
||||||
|
}
|
||||||
|
if (id.includes('node_modules/cropperjs/') || id.includes('node_modules/vue-cropperjs/')) {
|
||||||
|
return 'cropper'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通用 node_modules 分离
|
||||||
|
if (id.includes('node_modules/')) {
|
||||||
|
return 'vendor'
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
chunkFileNames: 'assets/js/[name]-[hash].js',
|
||||||
|
entryFileNames: 'assets/js/[name]-[hash].js',
|
||||||
|
assetFileNames: (assetInfo: any) => {
|
||||||
|
// 根据资源类型分类存放
|
||||||
|
const info = assetInfo.name?.split('.') ?? []
|
||||||
|
const ext = info[info.length - 1]
|
||||||
|
if (/png|jpe?g|svg|gif|tiff|bmp|ico/i.test(ext)) {
|
||||||
|
return 'assets/images/[name]-[hash][extname]'
|
||||||
|
}
|
||||||
|
if (/woff2?|ttf|otf|eot/i.test(ext)) {
|
||||||
|
return 'assets/fonts/[name]-[hash][extname]'
|
||||||
|
}
|
||||||
|
if (/css/i.test(ext)) {
|
||||||
|
return 'assets/css/[name]-[hash][extname]'
|
||||||
|
}
|
||||||
|
return 'assets/[ext]/[name]-[hash][extname]'
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user