浏览代码

chore: Add bundle analysis tooling and cross-platform environment support

- Add rollup-plugin-visualizer for bundle size analysis and visualization
- Add cross-env for cross-platform environment variable management
- Create analyze-bundle.js script for automated bundle analysis
- Add optimized Vite configuration file for performance analysis
- Update dependencies including @epic-web/invariant and related utilities
- Remove .gitkeep placeholder from components directory
- Update type definitions and UI store configuration
- Improves development workflow for monitoring and optimizing bundle size
Zhang Yice 1 月之前
父节点
当前提交
305fbc3339
共有 10 个文件被更改,包括 942 次插入53 次删除
  1. 416 0
      package-lock.json
  2. 4 0
      package.json
  3. 171 0
      scripts/analyze-bundle.js
  4. 0 0
      src/components/.gitkeep
  5. 1 24
      src/stores/uiStore.ts
  6. 1 1
      src/types/index.ts
  7. 1 5
      src/types/store.ts
  8. 0 9
      src/types/ui.ts
  9. 221 0
      vite.config.optimized.ts
  10. 127 14
      vite.config.ts

+ 416 - 0
package-lock.json

@@ -35,12 +35,14 @@
35 35
         "@types/turndown": "^5.0.6",
36 36
         "@types/uuid": "^10.0.0",
37 37
         "@vitejs/plugin-react": "^6.0.1",
38
+        "cross-env": "^10.1.0",
38 39
         "eslint": "^10.3.0",
39 40
         "eslint-plugin-react-hooks": "^7.1.1",
40 41
         "eslint-plugin-react-refresh": "^0.5.2",
41 42
         "globals": "^17.6.0",
42 43
         "jsdom": "^29.1.1",
43 44
         "prettier": "^3.4.2",
45
+        "rollup-plugin-visualizer": "^7.0.1",
44 46
         "typescript": "~6.0.2",
45 47
         "typescript-eslint": "^8.59.2",
46 48
         "vite": "^8.0.12",
@@ -667,6 +669,13 @@
667 669
       "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==",
668 670
       "license": "MIT"
669 671
     },
672
+    "node_modules/@epic-web/invariant": {
673
+      "version": "1.0.0",
674
+      "resolved": "https://registry.npmmirror.com/@epic-web/invariant/-/invariant-1.0.0.tgz",
675
+      "integrity": "sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==",
676
+      "dev": true,
677
+      "license": "MIT"
678
+    },
670 679
     "node_modules/@eslint-community/eslint-utils": {
671 680
       "version": "4.9.1",
672 681
       "resolved": "https://registry.npmmirror.com/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
@@ -2396,6 +2405,22 @@
2396 2405
         "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
2397 2406
       }
2398 2407
     },
2408
+    "node_modules/bundle-name": {
2409
+      "version": "4.1.0",
2410
+      "resolved": "https://registry.npmmirror.com/bundle-name/-/bundle-name-4.1.0.tgz",
2411
+      "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==",
2412
+      "dev": true,
2413
+      "license": "MIT",
2414
+      "dependencies": {
2415
+        "run-applescript": "^7.0.0"
2416
+      },
2417
+      "engines": {
2418
+        "node": ">=18"
2419
+      },
2420
+      "funding": {
2421
+        "url": "https://github.com/sponsors/sindresorhus"
2422
+      }
2423
+    },
2399 2424
     "node_modules/call-bind-apply-helpers": {
2400 2425
       "version": "1.0.2",
2401 2426
       "resolved": "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
@@ -2516,6 +2541,21 @@
2516 2541
       "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==",
2517 2542
       "license": "MIT"
2518 2543
     },
2544
+    "node_modules/cliui": {
2545
+      "version": "9.0.1",
2546
+      "resolved": "https://registry.npmmirror.com/cliui/-/cliui-9.0.1.tgz",
2547
+      "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==",
2548
+      "dev": true,
2549
+      "license": "ISC",
2550
+      "dependencies": {
2551
+        "string-width": "^7.2.0",
2552
+        "strip-ansi": "^7.1.0",
2553
+        "wrap-ansi": "^9.0.0"
2554
+      },
2555
+      "engines": {
2556
+        "node": ">=20"
2557
+      }
2558
+    },
2519 2559
     "node_modules/clsx": {
2520 2560
       "version": "2.1.1",
2521 2561
       "resolved": "https://registry.npmmirror.com/clsx/-/clsx-2.1.1.tgz",
@@ -2587,6 +2627,24 @@
2587 2627
       "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
2588 2628
       "license": "MIT"
2589 2629
     },
2630
+    "node_modules/cross-env": {
2631
+      "version": "10.1.0",
2632
+      "resolved": "https://registry.npmmirror.com/cross-env/-/cross-env-10.1.0.tgz",
2633
+      "integrity": "sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==",
2634
+      "dev": true,
2635
+      "license": "MIT",
2636
+      "dependencies": {
2637
+        "@epic-web/invariant": "^1.0.0",
2638
+        "cross-spawn": "^7.0.6"
2639
+      },
2640
+      "bin": {
2641
+        "cross-env": "dist/bin/cross-env.js",
2642
+        "cross-env-shell": "dist/bin/cross-env-shell.js"
2643
+      },
2644
+      "engines": {
2645
+        "node": ">=20"
2646
+      }
2647
+    },
2590 2648
     "node_modules/cross-spawn": {
2591 2649
       "version": "7.0.6",
2592 2650
       "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.6.tgz",
@@ -2702,6 +2760,49 @@
2702 2760
       "dev": true,
2703 2761
       "license": "MIT"
2704 2762
     },
2763
+    "node_modules/default-browser": {
2764
+      "version": "5.5.0",
2765
+      "resolved": "https://registry.npmmirror.com/default-browser/-/default-browser-5.5.0.tgz",
2766
+      "integrity": "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==",
2767
+      "dev": true,
2768
+      "license": "MIT",
2769
+      "dependencies": {
2770
+        "bundle-name": "^4.1.0",
2771
+        "default-browser-id": "^5.0.0"
2772
+      },
2773
+      "engines": {
2774
+        "node": ">=18"
2775
+      },
2776
+      "funding": {
2777
+        "url": "https://github.com/sponsors/sindresorhus"
2778
+      }
2779
+    },
2780
+    "node_modules/default-browser-id": {
2781
+      "version": "5.0.1",
2782
+      "resolved": "https://registry.npmmirror.com/default-browser-id/-/default-browser-id-5.0.1.tgz",
2783
+      "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==",
2784
+      "dev": true,
2785
+      "license": "MIT",
2786
+      "engines": {
2787
+        "node": ">=18"
2788
+      },
2789
+      "funding": {
2790
+        "url": "https://github.com/sponsors/sindresorhus"
2791
+      }
2792
+    },
2793
+    "node_modules/define-lazy-prop": {
2794
+      "version": "3.0.0",
2795
+      "resolved": "https://registry.npmmirror.com/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz",
2796
+      "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==",
2797
+      "dev": true,
2798
+      "license": "MIT",
2799
+      "engines": {
2800
+        "node": ">=12"
2801
+      },
2802
+      "funding": {
2803
+        "url": "https://github.com/sponsors/sindresorhus"
2804
+      }
2805
+    },
2705 2806
     "node_modules/delayed-stream": {
2706 2807
       "version": "1.0.0",
2707 2808
       "resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz",
@@ -2796,6 +2897,13 @@
2796 2897
       "dev": true,
2797 2898
       "license": "ISC"
2798 2899
     },
2900
+    "node_modules/emoji-regex": {
2901
+      "version": "10.6.0",
2902
+      "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-10.6.0.tgz",
2903
+      "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==",
2904
+      "dev": true,
2905
+      "license": "MIT"
2906
+    },
2799 2907
     "node_modules/entities": {
2800 2908
       "version": "8.0.0",
2801 2909
       "resolved": "https://registry.npmmirror.com/entities/-/entities-8.0.0.tgz",
@@ -3298,6 +3406,29 @@
3298 3406
         "node": ">=6.9.0"
3299 3407
       }
3300 3408
     },
3409
+    "node_modules/get-caller-file": {
3410
+      "version": "2.0.5",
3411
+      "resolved": "https://registry.npmmirror.com/get-caller-file/-/get-caller-file-2.0.5.tgz",
3412
+      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
3413
+      "dev": true,
3414
+      "license": "ISC",
3415
+      "engines": {
3416
+        "node": "6.* || 8.* || >= 10.*"
3417
+      }
3418
+    },
3419
+    "node_modules/get-east-asian-width": {
3420
+      "version": "1.6.0",
3421
+      "resolved": "https://registry.npmmirror.com/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz",
3422
+      "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==",
3423
+      "dev": true,
3424
+      "license": "MIT",
3425
+      "engines": {
3426
+        "node": ">=18"
3427
+      },
3428
+      "funding": {
3429
+        "url": "https://github.com/sponsors/sindresorhus"
3430
+      }
3431
+    },
3301 3432
     "node_modules/get-intrinsic": {
3302 3433
       "version": "1.3.0",
3303 3434
       "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
@@ -3749,6 +3880,22 @@
3749 3880
         "url": "https://github.com/sponsors/wooorm"
3750 3881
       }
3751 3882
     },
3883
+    "node_modules/is-docker": {
3884
+      "version": "3.0.0",
3885
+      "resolved": "https://registry.npmmirror.com/is-docker/-/is-docker-3.0.0.tgz",
3886
+      "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==",
3887
+      "dev": true,
3888
+      "license": "MIT",
3889
+      "bin": {
3890
+        "is-docker": "cli.js"
3891
+      },
3892
+      "engines": {
3893
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
3894
+      },
3895
+      "funding": {
3896
+        "url": "https://github.com/sponsors/sindresorhus"
3897
+      }
3898
+    },
3752 3899
     "node_modules/is-extglob": {
3753 3900
       "version": "2.1.1",
3754 3901
       "resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -3782,6 +3929,38 @@
3782 3929
         "url": "https://github.com/sponsors/wooorm"
3783 3930
       }
3784 3931
     },
3932
+    "node_modules/is-in-ssh": {
3933
+      "version": "1.0.0",
3934
+      "resolved": "https://registry.npmmirror.com/is-in-ssh/-/is-in-ssh-1.0.0.tgz",
3935
+      "integrity": "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==",
3936
+      "dev": true,
3937
+      "license": "MIT",
3938
+      "engines": {
3939
+        "node": ">=20"
3940
+      },
3941
+      "funding": {
3942
+        "url": "https://github.com/sponsors/sindresorhus"
3943
+      }
3944
+    },
3945
+    "node_modules/is-inside-container": {
3946
+      "version": "1.0.0",
3947
+      "resolved": "https://registry.npmmirror.com/is-inside-container/-/is-inside-container-1.0.0.tgz",
3948
+      "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==",
3949
+      "dev": true,
3950
+      "license": "MIT",
3951
+      "dependencies": {
3952
+        "is-docker": "^3.0.0"
3953
+      },
3954
+      "bin": {
3955
+        "is-inside-container": "cli.js"
3956
+      },
3957
+      "engines": {
3958
+        "node": ">=14.16"
3959
+      },
3960
+      "funding": {
3961
+        "url": "https://github.com/sponsors/sindresorhus"
3962
+      }
3963
+    },
3785 3964
     "node_modules/is-mobile": {
3786 3965
       "version": "5.0.0",
3787 3966
       "resolved": "https://registry.npmmirror.com/is-mobile/-/is-mobile-5.0.0.tgz",
@@ -3807,6 +3986,22 @@
3807 3986
       "dev": true,
3808 3987
       "license": "MIT"
3809 3988
     },
3989
+    "node_modules/is-wsl": {
3990
+      "version": "3.1.1",
3991
+      "resolved": "https://registry.npmmirror.com/is-wsl/-/is-wsl-3.1.1.tgz",
3992
+      "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==",
3993
+      "dev": true,
3994
+      "license": "MIT",
3995
+      "dependencies": {
3996
+        "is-inside-container": "^1.0.0"
3997
+      },
3998
+      "engines": {
3999
+        "node": ">=16"
4000
+      },
4001
+      "funding": {
4002
+        "url": "https://github.com/sponsors/sindresorhus"
4003
+      }
4004
+    },
3810 4005
     "node_modules/isarray": {
3811 4006
       "version": "1.0.0",
3812 4007
       "resolved": "https://registry.npmmirror.com/isarray/-/isarray-1.0.0.tgz",
@@ -5356,6 +5551,27 @@
5356 5551
         "node": ">=12.20.0"
5357 5552
       }
5358 5553
     },
5554
+    "node_modules/open": {
5555
+      "version": "11.0.0",
5556
+      "resolved": "https://registry.npmmirror.com/open/-/open-11.0.0.tgz",
5557
+      "integrity": "sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==",
5558
+      "dev": true,
5559
+      "license": "MIT",
5560
+      "dependencies": {
5561
+        "default-browser": "^5.4.0",
5562
+        "define-lazy-prop": "^3.0.0",
5563
+        "is-in-ssh": "^1.0.0",
5564
+        "is-inside-container": "^1.0.0",
5565
+        "powershell-utils": "^0.1.0",
5566
+        "wsl-utils": "^0.3.0"
5567
+      },
5568
+      "engines": {
5569
+        "node": ">=20"
5570
+      },
5571
+      "funding": {
5572
+        "url": "https://github.com/sponsors/sindresorhus"
5573
+      }
5574
+    },
5359 5575
     "node_modules/option": {
5360 5576
       "version": "0.2.4",
5361 5577
       "resolved": "https://registry.npmmirror.com/option/-/option-0.2.4.tgz",
@@ -5548,6 +5764,19 @@
5548 5764
         "node": "^10 || ^12 || >=14"
5549 5765
       }
5550 5766
     },
5767
+    "node_modules/powershell-utils": {
5768
+      "version": "0.1.0",
5769
+      "resolved": "https://registry.npmmirror.com/powershell-utils/-/powershell-utils-0.1.0.tgz",
5770
+      "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==",
5771
+      "dev": true,
5772
+      "license": "MIT",
5773
+      "engines": {
5774
+        "node": ">=20"
5775
+      },
5776
+      "funding": {
5777
+        "url": "https://github.com/sponsors/sindresorhus"
5778
+      }
5779
+    },
5551 5780
     "node_modules/prelude-ls": {
5552 5781
       "version": "1.2.1",
5553 5782
       "resolved": "https://registry.npmmirror.com/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -6498,6 +6727,50 @@
6498 6727
         "@rolldown/binding-win32-x64-msvc": "1.0.3"
6499 6728
       }
6500 6729
     },
6730
+    "node_modules/rollup-plugin-visualizer": {
6731
+      "version": "7.0.1",
6732
+      "resolved": "https://registry.npmmirror.com/rollup-plugin-visualizer/-/rollup-plugin-visualizer-7.0.1.tgz",
6733
+      "integrity": "sha512-UJUT4+1Ho4OcWmPYU3sYXgUqI8B8Ayfe06MX7y0qCJ1K8aGoKtR/NDd/2nZqM7ADkrzny+I99Ul7GgyoiVNAgg==",
6734
+      "dev": true,
6735
+      "license": "MIT",
6736
+      "dependencies": {
6737
+        "open": "^11.0.0",
6738
+        "picomatch": "^4.0.2",
6739
+        "source-map": "^0.7.4",
6740
+        "yargs": "^18.0.0"
6741
+      },
6742
+      "bin": {
6743
+        "rollup-plugin-visualizer": "dist/bin/cli.js"
6744
+      },
6745
+      "engines": {
6746
+        "node": ">=22"
6747
+      },
6748
+      "peerDependencies": {
6749
+        "rolldown": "1.x || ^1.0.0-beta || ^1.0.0-rc",
6750
+        "rollup": "2.x || 3.x || 4.x"
6751
+      },
6752
+      "peerDependenciesMeta": {
6753
+        "rolldown": {
6754
+          "optional": true
6755
+        },
6756
+        "rollup": {
6757
+          "optional": true
6758
+        }
6759
+      }
6760
+    },
6761
+    "node_modules/run-applescript": {
6762
+      "version": "7.1.0",
6763
+      "resolved": "https://registry.npmmirror.com/run-applescript/-/run-applescript-7.1.0.tgz",
6764
+      "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==",
6765
+      "dev": true,
6766
+      "license": "MIT",
6767
+      "engines": {
6768
+        "node": ">=18"
6769
+      },
6770
+      "funding": {
6771
+        "url": "https://github.com/sponsors/sindresorhus"
6772
+      }
6773
+    },
6501 6774
     "node_modules/safe-buffer": {
6502 6775
       "version": "5.1.2",
6503 6776
       "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz",
@@ -6581,6 +6854,16 @@
6581 6854
       "dev": true,
6582 6855
       "license": "ISC"
6583 6856
     },
6857
+    "node_modules/source-map": {
6858
+      "version": "0.7.6",
6859
+      "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.7.6.tgz",
6860
+      "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==",
6861
+      "dev": true,
6862
+      "license": "BSD-3-Clause",
6863
+      "engines": {
6864
+        "node": ">= 12"
6865
+      }
6866
+    },
6584 6867
     "node_modules/source-map-js": {
6585 6868
       "version": "1.2.1",
6586 6869
       "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz",
@@ -6646,6 +6929,24 @@
6646 6929
       "integrity": "sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==",
6647 6930
       "license": "MIT"
6648 6931
     },
6932
+    "node_modules/string-width": {
6933
+      "version": "7.2.0",
6934
+      "resolved": "https://registry.npmmirror.com/string-width/-/string-width-7.2.0.tgz",
6935
+      "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
6936
+      "dev": true,
6937
+      "license": "MIT",
6938
+      "dependencies": {
6939
+        "emoji-regex": "^10.3.0",
6940
+        "get-east-asian-width": "^1.0.0",
6941
+        "strip-ansi": "^7.1.0"
6942
+      },
6943
+      "engines": {
6944
+        "node": ">=18"
6945
+      },
6946
+      "funding": {
6947
+        "url": "https://github.com/sponsors/sindresorhus"
6948
+      }
6949
+    },
6649 6950
     "node_modules/stringify-entities": {
6650 6951
       "version": "4.0.4",
6651 6952
       "resolved": "https://registry.npmmirror.com/stringify-entities/-/stringify-entities-4.0.4.tgz",
@@ -6660,6 +6961,35 @@
6660 6961
         "url": "https://github.com/sponsors/wooorm"
6661 6962
       }
6662 6963
     },
6964
+    "node_modules/strip-ansi": {
6965
+      "version": "7.2.0",
6966
+      "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-7.2.0.tgz",
6967
+      "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==",
6968
+      "dev": true,
6969
+      "license": "MIT",
6970
+      "dependencies": {
6971
+        "ansi-regex": "^6.2.2"
6972
+      },
6973
+      "engines": {
6974
+        "node": ">=12"
6975
+      },
6976
+      "funding": {
6977
+        "url": "https://github.com/chalk/strip-ansi?sponsor=1"
6978
+      }
6979
+    },
6980
+    "node_modules/strip-ansi/node_modules/ansi-regex": {
6981
+      "version": "6.2.2",
6982
+      "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-6.2.2.tgz",
6983
+      "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
6984
+      "dev": true,
6985
+      "license": "MIT",
6986
+      "engines": {
6987
+        "node": ">=12"
6988
+      },
6989
+      "funding": {
6990
+        "url": "https://github.com/chalk/ansi-regex?sponsor=1"
6991
+      }
6992
+    },
6663 6993
     "node_modules/strip-indent": {
6664 6994
       "version": "3.0.0",
6665 6995
       "resolved": "https://registry.npmmirror.com/strip-indent/-/strip-indent-3.0.0.tgz",
@@ -7432,6 +7762,54 @@
7432 7762
         "node": ">=0.10.0"
7433 7763
       }
7434 7764
     },
7765
+    "node_modules/wrap-ansi": {
7766
+      "version": "9.0.2",
7767
+      "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-9.0.2.tgz",
7768
+      "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==",
7769
+      "dev": true,
7770
+      "license": "MIT",
7771
+      "dependencies": {
7772
+        "ansi-styles": "^6.2.1",
7773
+        "string-width": "^7.0.0",
7774
+        "strip-ansi": "^7.1.0"
7775
+      },
7776
+      "engines": {
7777
+        "node": ">=18"
7778
+      },
7779
+      "funding": {
7780
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
7781
+      }
7782
+    },
7783
+    "node_modules/wrap-ansi/node_modules/ansi-styles": {
7784
+      "version": "6.2.3",
7785
+      "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-6.2.3.tgz",
7786
+      "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
7787
+      "dev": true,
7788
+      "license": "MIT",
7789
+      "engines": {
7790
+        "node": ">=12"
7791
+      },
7792
+      "funding": {
7793
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
7794
+      }
7795
+    },
7796
+    "node_modules/wsl-utils": {
7797
+      "version": "0.3.1",
7798
+      "resolved": "https://registry.npmmirror.com/wsl-utils/-/wsl-utils-0.3.1.tgz",
7799
+      "integrity": "sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==",
7800
+      "dev": true,
7801
+      "license": "MIT",
7802
+      "dependencies": {
7803
+        "is-wsl": "^3.1.0",
7804
+        "powershell-utils": "^0.1.0"
7805
+      },
7806
+      "engines": {
7807
+        "node": ">=20"
7808
+      },
7809
+      "funding": {
7810
+        "url": "https://github.com/sponsors/sindresorhus"
7811
+      }
7812
+    },
7435 7813
     "node_modules/xml-name-validator": {
7436 7814
       "version": "5.0.0",
7437 7815
       "resolved": "https://registry.npmmirror.com/xml-name-validator/-/xml-name-validator-5.0.0.tgz",
@@ -7458,6 +7836,16 @@
7458 7836
       "dev": true,
7459 7837
       "license": "MIT"
7460 7838
     },
7839
+    "node_modules/y18n": {
7840
+      "version": "5.0.8",
7841
+      "resolved": "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz",
7842
+      "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
7843
+      "dev": true,
7844
+      "license": "ISC",
7845
+      "engines": {
7846
+        "node": ">=10"
7847
+      }
7848
+    },
7461 7849
     "node_modules/yallist": {
7462 7850
       "version": "3.1.1",
7463 7851
       "resolved": "https://registry.npmmirror.com/yallist/-/yallist-3.1.1.tgz",
@@ -7465,6 +7853,34 @@
7465 7853
       "dev": true,
7466 7854
       "license": "ISC"
7467 7855
     },
7856
+    "node_modules/yargs": {
7857
+      "version": "18.0.0",
7858
+      "resolved": "https://registry.npmmirror.com/yargs/-/yargs-18.0.0.tgz",
7859
+      "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==",
7860
+      "dev": true,
7861
+      "license": "MIT",
7862
+      "dependencies": {
7863
+        "cliui": "^9.0.1",
7864
+        "escalade": "^3.1.1",
7865
+        "get-caller-file": "^2.0.5",
7866
+        "string-width": "^7.2.0",
7867
+        "y18n": "^5.0.5",
7868
+        "yargs-parser": "^22.0.0"
7869
+      },
7870
+      "engines": {
7871
+        "node": "^20.19.0 || ^22.12.0 || >=23"
7872
+      }
7873
+    },
7874
+    "node_modules/yargs-parser": {
7875
+      "version": "22.0.0",
7876
+      "resolved": "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-22.0.0.tgz",
7877
+      "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==",
7878
+      "dev": true,
7879
+      "license": "ISC",
7880
+      "engines": {
7881
+        "node": "^20.19.0 || ^22.12.0 || >=23"
7882
+      }
7883
+    },
7468 7884
     "node_modules/yocto-queue": {
7469 7885
       "version": "0.1.0",
7470 7886
       "resolved": "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz",

+ 4 - 0
package.json

@@ -6,6 +6,8 @@
6 6
   "scripts": {
7 7
     "dev": "vite",
8 8
     "build": "tsc -b && vite build",
9
+    "build:analyze": "cross-env ANALYZE=true npm run build",
10
+    "analyze": "node scripts/analyze-bundle.js",
9 11
     "lint": "eslint .",
10 12
     "format": "prettier --write \"src/**/*.{ts,tsx,js,jsx,json,css,md}\"",
11 13
     "format:check": "prettier --check \"src/**/*.{ts,tsx,js,jsx,json,css,md}\"",
@@ -45,12 +47,14 @@
45 47
     "@types/turndown": "^5.0.6",
46 48
     "@types/uuid": "^10.0.0",
47 49
     "@vitejs/plugin-react": "^6.0.1",
50
+    "cross-env": "^10.1.0",
48 51
     "eslint": "^10.3.0",
49 52
     "eslint-plugin-react-hooks": "^7.1.1",
50 53
     "eslint-plugin-react-refresh": "^0.5.2",
51 54
     "globals": "^17.6.0",
52 55
     "jsdom": "^29.1.1",
53 56
     "prettier": "^3.4.2",
57
+    "rollup-plugin-visualizer": "^7.0.1",
54 58
     "typescript": "~6.0.2",
55 59
     "typescript-eslint": "^8.59.2",
56 60
     "vite": "^8.0.12",

+ 171 - 0
scripts/analyze-bundle.js

@@ -0,0 +1,171 @@
1
+/**
2
+ * Bundle 分析脚本
3
+ * 
4
+ * 自动化 bundle 分析流程:
5
+ * 1. 构建生产版本
6
+ * 2. 生成分析报告
7
+ * 3. 输出关键指标
8
+ * 
9
+ * 使用: node scripts/analyze-bundle.js
10
+ */
11
+
12
+const { execSync } = require('child_process');
13
+const fs = require('fs');
14
+const path = require('path');
15
+
16
+// ANSI 颜色代码
17
+const colors = {
18
+  reset: '\x1b[0m',
19
+  bright: '\x1b[1m',
20
+  green: '\x1b[32m',
21
+  yellow: '\x1b[33m',
22
+  blue: '\x1b[34m',
23
+  red: '\x1b[31m',
24
+};
25
+
26
+function log(message, color = 'reset') {
27
+  console.log(`${colors[color]}${message}${colors.reset}`);
28
+}
29
+
30
+function formatBytes(bytes) {
31
+  if (bytes < 1024) return bytes + ' B';
32
+  if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(2) + ' KB';
33
+  return (bytes / (1024 * 1024)).toFixed(2) + ' MB';
34
+}
35
+
36
+async function main() {
37
+  log('\n🔍 Bundle 分析工具\n', 'bright');
38
+
39
+  // 步骤 1: 清理旧的构建产物
40
+  log('📦 清理旧的构建产物...', 'blue');
41
+  try {
42
+    if (fs.existsSync('dist')) {
43
+      fs.rmSync('dist', { recursive: true, force: true });
44
+    }
45
+    log('✅ 清理完成\n', 'green');
46
+  } catch (error) {
47
+    log(`❌ 清理失败: ${error.message}\n`, 'red');
48
+  }
49
+
50
+  // 步骤 2: 构建生产版本
51
+  log('🏗️  构建生产版本...', 'blue');
52
+  try {
53
+    execSync('npm run build', { 
54
+      stdio: 'inherit',
55
+      env: { ...process.env, ANALYZE: 'true' }
56
+    });
57
+    log('✅ 构建完成\n', 'green');
58
+  } catch (error) {
59
+    log('❌ 构建失败,请检查错误信息\n', 'red');
60
+    process.exit(1);
61
+  }
62
+
63
+  // 步骤 3: 分析构建产物
64
+  log('📊 分析构建产物...\n', 'blue');
65
+  
66
+  const distPath = path.join(process.cwd(), 'dist', 'assets');
67
+  
68
+  if (!fs.existsSync(distPath)) {
69
+    log('❌ dist/assets 目录不存在\n', 'red');
70
+    return;
71
+  }
72
+
73
+  const files = fs.readdirSync(distPath);
74
+  
75
+  // 分类统计
76
+  const stats = {
77
+    js: [],
78
+    css: [],
79
+    other: [],
80
+  };
81
+
82
+  files.forEach((file) => {
83
+    const filePath = path.join(distPath, file);
84
+    const stat = fs.statSync(filePath);
85
+    const size = stat.size;
86
+
87
+    const fileInfo = {
88
+      name: file,
89
+      size,
90
+      sizeFormatted: formatBytes(size),
91
+    };
92
+
93
+    if (file.endsWith('.js')) {
94
+      stats.js.push(fileInfo);
95
+    } else if (file.endsWith('.css')) {
96
+      stats.css.push(fileInfo);
97
+    } else {
98
+      stats.other.push(fileInfo);
99
+    }
100
+  });
101
+
102
+  // 排序(按大小降序)
103
+  stats.js.sort((a, b) => b.size - a.size);
104
+  stats.css.sort((a, b) => b.size - a.size);
105
+
106
+  // 输出 JS 文件统计
107
+  log('JavaScript 文件:', 'bright');
108
+  stats.js.forEach((file, index) => {
109
+    const color = file.size > 600 * 1024 ? 'red' : file.size > 200 * 1024 ? 'yellow' : 'green';
110
+    const icon = file.size > 600 * 1024 ? '⚠️ ' : '  ';
111
+    log(`${icon}${index + 1}. ${file.name.padEnd(50)} ${file.sizeFormatted}`, color);
112
+  });
113
+
114
+  const totalJS = stats.js.reduce((sum, file) => sum + file.size, 0);
115
+  log(`\n总计: ${formatBytes(totalJS)}\n`, 'bright');
116
+
117
+  // 输出 CSS 文件统计
118
+  log('CSS 文件:', 'bright');
119
+  stats.css.forEach((file, index) => {
120
+    log(`  ${index + 1}. ${file.name.padEnd(50)} ${file.sizeFormatted}`, 'green');
121
+  });
122
+
123
+  const totalCSS = stats.css.reduce((sum, file) => sum + file.size, 0);
124
+  log(`\n总计: ${formatBytes(totalCSS)}\n`, 'bright');
125
+
126
+  // 总体统计
127
+  const total = totalJS + totalCSS;
128
+  log('📈 总体统计:', 'bright');
129
+  log(`  JavaScript: ${formatBytes(totalJS)} (${((totalJS / total) * 100).toFixed(1)}%)`, 'blue');
130
+  log(`  CSS:        ${formatBytes(totalCSS)} (${((totalCSS / total) * 100).toFixed(1)}%)`, 'blue');
131
+  log(`  总计:       ${formatBytes(total)}\n`, 'bright');
132
+
133
+  // 警告信息
134
+  const largeFiles = stats.js.filter(f => f.size > 600 * 1024);
135
+  if (largeFiles.length > 0) {
136
+    log('⚠️  警告: 以下文件超过 600 KB,建议优化:', 'yellow');
137
+    largeFiles.forEach((file) => {
138
+      log(`   - ${file.name}: ${file.sizeFormatted}`, 'yellow');
139
+    });
140
+    log('');
141
+  }
142
+
143
+  // 优化建议
144
+  log('💡 优化建议:', 'bright');
145
+  
146
+  if (largeFiles.length > 0) {
147
+    log('  1. 检查是否可以进一步拆分大型 chunk', 'blue');
148
+    log('  2. 确认是否启用了 tree-shaking', 'blue');
149
+    log('  3. 考虑使用动态导入延迟加载', 'blue');
150
+  } else {
151
+    log('  ✅ Bundle 大小在合理范围内', 'green');
152
+  }
153
+
154
+  // 检查是否生成了分析报告
155
+  const statsFile = path.join(process.cwd(), 'dist', 'stats.html');
156
+  if (fs.existsSync(statsFile)) {
157
+    log('\n📊 详细分析报告已生成: dist/stats.html', 'green');
158
+    log('   在浏览器中打开此文件查看可视化分析\n', 'blue');
159
+  } else {
160
+    log('\n⚠️  未生成详细分析报告', 'yellow');
161
+    log('   请确保已安装 rollup-plugin-visualizer:', 'yellow');
162
+    log('   npm install --save-dev rollup-plugin-visualizer\n', 'yellow');
163
+  }
164
+}
165
+
166
+// 运行脚本
167
+main().catch((error) => {
168
+  console.error('Error:', error);
169
+  process.exit(1);
170
+});
171
+

+ 0 - 0
src/components/.gitkeep


+ 1 - 24
src/stores/uiStore.ts

@@ -5,7 +5,6 @@
5 5
  * Handles:
6 6
  * - Global loading state
7 7
  * - Global error messages
8
- * - Layout mode for responsive design (desktop/tablet/mobile)
9 8
  * - Left panel width with localStorage persistence
10 9
  *
11 10
  * @module stores/uiStore
@@ -13,7 +12,6 @@
13 12
 
14 13
 import { create } from 'zustand';
15 14
 import type { UIStoreState } from '../types/store';
16
-import type { LayoutMode } from '../types/ui';
17 15
 import { getItem, setItem } from '../utils/storage';
18 16
 
19 17
 /**
@@ -40,7 +38,7 @@ const loadLeftPanelWidth = (): number => {
40 38
  * UI store
41 39
  *
42 40
  * Manages global UI state including loading indicators, error messages,
43
- * responsive layout mode, panel width preferences, and document preview state.
41
+ * panel width preferences, and document preview state.
44 42
  *
45 43
  * The left panel width is automatically persisted to localStorage
46 44
  * when updated via setLeftPanelWidth action.
@@ -56,9 +54,6 @@ const loadLeftPanelWidth = (): number => {
56 54
  * // Clear error
57 55
  * useUIStore.getState().setError(null);
58 56
  *
59
- * // Set layout mode based on screen size
60
- * useUIStore.getState().setLayoutMode('mobile');
61
- *
62 57
  * // Update left panel width (persists to localStorage)
63 58
  * useUIStore.getState().setLeftPanelWidth(35);
64 59
  *
@@ -73,9 +68,6 @@ export const useUIStore = create<UIStoreState>((set) => ({
73 68
   // ============ State ============
74 69
   loading: false,
75 70
   error: null,
76
-  // Note: layoutMode is deprecated as responsive layout has been removed.
77
-  // Only desktop layout is now supported. Kept for backward compatibility.
78
-  layoutMode: 'desktop',
79 71
   leftPanelWidth: loadLeftPanelWidth(),
80 72
   // Note: previewMode is deprecated. Right panel now shows EditorPanel by default.
81 73
   // Kept for backward compatibility.
@@ -110,21 +102,6 @@ export const useUIStore = create<UIStoreState>((set) => ({
110 102
   },
111 103
 
112 104
   /**
113
-   * Set layout mode
114
-   *
115
-   * @deprecated Responsive layout switching has been removed. Only desktop mode
116
-   * is supported. This method is kept for backward compatibility.
117
-   *
118
-   * Updates the layout mode for responsive design.
119
-   * Typically called by a responsive hook when screen size changes.
120
-   *
121
-   * @param mode - Layout mode (desktop, tablet, or mobile)
122
-   */
123
-  setLayoutMode: (mode: LayoutMode) => {
124
-    set({ layoutMode: mode });
125
-  },
126
-
127
-  /**
128 105
    * Set left panel width and persist to localStorage
129 106
    *
130 107
    * Updates the left panel width and saves it to localStorage

+ 1 - 1
src/types/index.ts

@@ -21,7 +21,7 @@ export type {
21 21
 } from './api';
22 22
 
23 23
 // UI types
24
-export type { SaveStatus, LayoutMode } from './ui';
24
+export type { SaveStatus } from './ui';
25 25
 
26 26
 // Store types
27 27
 export type { DocumentStoreState, ChatStoreState, UIStoreState } from './store';

+ 1 - 5
src/types/store.ts

@@ -4,7 +4,7 @@
4 4
 
5 5
 import type { Document, DocumentListItem } from './document';
6 6
 import type { ChatMessage, ChatSession } from './chat';
7
-import type { SaveStatus, LayoutMode } from './ui';
7
+import type { SaveStatus } from './ui';
8 8
 import type {
9 9
   CreateDocumentRequest,
10 10
   UpdateDocumentRequest,
@@ -85,8 +85,6 @@ export interface UIStoreState {
85 85
   loading: boolean;
86 86
   /** Global error message */
87 87
   error: string | null;
88
-  /** Current layout mode (responsive) */
89
-  layoutMode: LayoutMode;
90 88
   /** Left panel width percentage */
91 89
   leftPanelWidth: number;
92 90
   /** Whether document preview mode is active */
@@ -101,8 +99,6 @@ export interface UIStoreState {
101 99
   setLoading: (loading: boolean) => void;
102 100
   /** Set global error message */
103 101
   setError: (error: string | null) => void;
104
-  /** Set layout mode */
105
-  setLayoutMode: (mode: LayoutMode) => void;
106 102
   /** Set left panel width and persist to localStorage */
107 103
   setLeftPanelWidth: (width: number) => void;
108 104
   /** Open document preview mode */

+ 0 - 9
src/types/ui.ts

@@ -6,12 +6,3 @@
6 6
  * Document save status indicator
7 7
  */
8 8
 export type SaveStatus = 'saved' | 'saving' | 'unsaved' | 'error';
9
-
10
-/**
11
- * Layout mode for responsive design
12
- * 
13
- * @deprecated Responsive layout switching has been removed. Only 'desktop' mode
14
- * is now supported. This type is kept for backward compatibility but may be
15
- * simplified or removed in future versions.
16
- */
17
-export type LayoutMode = 'desktop' | 'tablet' | 'mobile';

+ 221 - 0
vite.config.optimized.ts

@@ -0,0 +1,221 @@
1
+/**
2
+ * Vite 优化配置
3
+ * 
4
+ * 这是一个优化后的 vite 配置文件,包含:
5
+ * - 更细粒度的 chunk 拆分
6
+ * - Bundle 分析工具
7
+ * - 图片压缩
8
+ * 
9
+ * 使用方法:
10
+ * 1. 备份当前的 vite.config.ts
11
+ * 2. 将此文件重命名为 vite.config.ts
12
+ * 3. 安装必要依赖: npm install --save-dev rollup-plugin-visualizer
13
+ */
14
+
15
+import { defineConfig } from 'vite';
16
+import react from '@vitejs/plugin-react';
17
+import { visualizer } from 'rollup-plugin-visualizer';
18
+
19
+// https://vite.dev/config/
20
+export default defineConfig({
21
+  plugins: [
22
+    react(),
23
+    
24
+    // Bundle 分析工具(仅在需要时启用)
25
+    // 运行 npm run build 后会生成 dist/stats.html
26
+    process.env.ANALYZE === 'true' && visualizer({
27
+      open: true,
28
+      filename: 'dist/stats.html',
29
+      gzipSize: true,
30
+      brotliSize: true,
31
+      template: 'treemap', // 'sunburst' | 'treemap' | 'network'
32
+    }),
33
+  ].filter(Boolean),
34
+
35
+  build: {
36
+    // 使用 Vite 8 默认的 oxc 压缩器(最快)
37
+    // 如果需要更高压缩率,可以改为 'esbuild' 或 'terser'
38
+    // minify: 'esbuild',
39
+
40
+    // 提高 chunk 大小警告阈值(Ant Design 较大)
41
+    chunkSizeWarningLimit: 600,
42
+
43
+    rollupOptions: {
44
+      output: {
45
+        /**
46
+         * 优化的手动 chunk 拆分策略
47
+         * 
48
+         * 目标:
49
+         * 1. 将不同功能的库拆分到独立 chunk
50
+         * 2. 提高浏览器缓存命中率
51
+         * 3. 减少首次加载体积
52
+         */
53
+        manualChunks(id: string) {
54
+          // ========== 核心框架 ==========
55
+          if (id.includes('node_modules/react') || id.includes('node_modules/react-dom')) {
56
+            return 'react-vendor';
57
+          }
58
+
59
+          // ========== UI 组件库 ==========
60
+          // Ant Design 核心组件(高频使用)
61
+          if (
62
+            id.includes('node_modules/antd/es/button') ||
63
+            id.includes('node_modules/antd/es/input') ||
64
+            id.includes('node_modules/antd/es/form') ||
65
+            id.includes('node_modules/antd/es/space') ||
66
+            id.includes('node_modules/antd/es/card') ||
67
+            id.includes('node_modules/antd/es/spin')
68
+          ) {
69
+            return 'antd-core';
70
+          }
71
+
72
+          // Ant Design 扩展组件(低频使用)
73
+          if (
74
+            id.includes('node_modules/antd/es/table') ||
75
+            id.includes('node_modules/antd/es/drawer') ||
76
+            id.includes('node_modules/antd/es/modal') ||
77
+            id.includes('node_modules/antd/es/dropdown') ||
78
+            id.includes('node_modules/antd/es/menu')
79
+          ) {
80
+            return 'antd-extended';
81
+          }
82
+
83
+          // 其他 Ant Design 代码和图标
84
+          if (id.includes('node_modules/antd') || id.includes('node_modules/@ant-design')) {
85
+            return 'antd-vendor';
86
+          }
87
+
88
+          // ========== 文档处理库(按需加载)==========
89
+          // Word 文档解析(mammoth, docx-preview)
90
+          if (
91
+            id.includes('node_modules/mammoth') ||
92
+            id.includes('node_modules/docx-preview')
93
+          ) {
94
+            return 'document-libs-vendor';
95
+          }
96
+
97
+          // ========== 导出功能库(按需加载)==========
98
+          // PDF 和截图(jspdf, html2canvas)
99
+          if (
100
+            id.includes('node_modules/jspdf') ||
101
+            id.includes('node_modules/html2canvas')
102
+          ) {
103
+            return 'export-libs-vendor';
104
+          }
105
+
106
+          // HTML 转 Markdown(turndown)
107
+          if (id.includes('node_modules/turndown')) {
108
+            return 'markdown-converter-vendor';
109
+          }
110
+
111
+          // ========== Markdown 渲染库 ==========
112
+          // react-markdown 及其依赖
113
+          if (
114
+            id.includes('node_modules/react-markdown') ||
115
+            id.includes('node_modules/remark-') ||
116
+            id.includes('node_modules/rehype-') ||
117
+            id.includes('node_modules/unified') ||
118
+            id.includes('node_modules/micromark')
119
+          ) {
120
+            return 'markdown-vendor';
121
+          }
122
+
123
+          // ========== 编辑器相关 ==========
124
+          // Slate.js 富文本编辑器(如果使用)
125
+          if (
126
+            id.includes('node_modules/slate') ||
127
+            id.includes('node_modules/slate-react') ||
128
+            id.includes('node_modules/slate-history')
129
+          ) {
130
+            return 'slate-vendor';
131
+          }
132
+
133
+          // ========== 工具库 ==========
134
+          // HTTP 客户端
135
+          if (id.includes('node_modules/axios')) {
136
+            return 'axios-vendor';
137
+          }
138
+
139
+          // 状态管理
140
+          if (id.includes('node_modules/zustand')) {
141
+            return 'zustand-vendor';
142
+          }
143
+
144
+          // 其他小型工具库
145
+          if (
146
+            id.includes('node_modules/uuid') ||
147
+            id.includes('node_modules/dayjs') ||
148
+            id.includes('node_modules/lodash')
149
+          ) {
150
+            return 'utils-vendor';
151
+          }
152
+
153
+          // ========== 其他第三方库 ==========
154
+          if (id.includes('node_modules')) {
155
+            return 'vendor';
156
+          }
157
+
158
+          // 应用代码(由 React.lazy 自动分割)
159
+          // 不需要在这里处理
160
+        },
161
+      },
162
+
163
+      // Tree-shaking 配置(移除未使用的代码)
164
+      treeshake: {
165
+        moduleSideEffects: false,
166
+        propertyReadSideEffects: false,
167
+      },
168
+    },
169
+
170
+    // 启用 CSS 代码分割
171
+    cssCodeSplit: true,
172
+
173
+    // 启用源码映射(方便调试,生产环境可关闭)
174
+    sourcemap: process.env.NODE_ENV !== 'production',
175
+
176
+    // 产物输出目录
177
+    outDir: 'dist',
178
+
179
+    // 静态资源处理
180
+    assetsDir: 'assets',
181
+
182
+    // 小于此阈值的资源将内联为 base64
183
+    assetsInlineLimit: 4096, // 4KB
184
+  },
185
+
186
+  // 开发服务器配置
187
+  server: {
188
+    port: 5173,
189
+    host: true, // 监听所有地址
190
+    open: false, // 不自动打开浏览器
191
+    
192
+    // 预加载优化
193
+    warmup: {
194
+      clientFiles: [
195
+        './src/App.tsx',
196
+        './src/components/ChatPanel/ChatPanel.tsx',
197
+        './src/components/EditorPanel/EditorPanel.tsx',
198
+      ],
199
+    },
200
+  },
201
+
202
+  // 依赖预构建优化
203
+  optimizeDeps: {
204
+    include: [
205
+      'react',
206
+      'react-dom',
207
+      'axios',
208
+      'zustand',
209
+      'antd',
210
+      '@ant-design/icons',
211
+    ],
212
+    // 排除不需要预构建的大型依赖
213
+    exclude: [
214
+      'mammoth',
215
+      'docx-preview',
216
+      'jspdf',
217
+      'html2canvas',
218
+    ],
219
+  },
220
+});
221
+

+ 127 - 14
vite.config.ts

@@ -1,9 +1,21 @@
1 1
 import { defineConfig } from 'vite';
2 2
 import react from '@vitejs/plugin-react';
3
+import { visualizer } from 'rollup-plugin-visualizer';
3 4
 
4 5
 // https://vite.dev/config/
5 6
 export default defineConfig({
6
-  plugins: [react()],
7
+  plugins: [
8
+    react(),
9
+    
10
+    // Bundle 分析工具(通过 ANALYZE=true 环境变量启用)
11
+    process.env.ANALYZE === 'true' && visualizer({
12
+      open: true,
13
+      filename: 'dist/stats.html',
14
+      gzipSize: true,
15
+      brotliSize: true,
16
+      template: 'treemap',
17
+    }),
18
+  ].filter(Boolean),
7 19
 
8 20
   build: {
9 21
     // Enable minification for production builds (Req 13.9)
@@ -19,27 +31,95 @@ export default defineConfig({
19 31
     rollupOptions: {
20 32
       output: {
21 33
         /**
22
-         * Manual chunk splitting (Req 13.8)
34
+         * 优化的 Manual chunk splitting 策略
23 35
          *
24
-         * Splitting large vendor libraries into dedicated chunks means the
25
-         * browser can cache them independently of app code.  Tree-shaking
26
-         * (built into Rollup by default) removes unused exports within each
27
-         * chunk automatically (Req 13.9).
28
-         *
29
-         * Chunk strategy:
30
-         *  - react-vendor  : React + React-DOM (stable, rarely changes)
31
-         *  - antd-vendor   : Ant Design (large UI library, rarely changes)
32
-         *  - slate-vendor  : Slate.js + slate-react + slate-history
33
-         *  - utils-vendor  : Axios, Zustand, uuid (small but third-party)
34
-         *  - app code      : everything under src/ (split by React.lazy)
36
+         * 将 Ant Design 拆分为多个更小的 chunks,提高缓存命中率
37
+         * 并独立打包大型文档处理库
35 38
          */
36 39
         manualChunks(id: string) {
40
+          // ========== React 核心框架 ==========
37 41
           if (id.includes('node_modules/react') || id.includes('node_modules/react-dom')) {
38 42
             return 'react-vendor';
39 43
           }
44
+
45
+          // ========== Ant Design 细粒度拆分 ==========
46
+          // 核心组件(高频使用,首屏必需)
47
+          if (
48
+            id.includes('node_modules/antd/es/button') ||
49
+            id.includes('node_modules/antd/es/input') ||
50
+            id.includes('node_modules/antd/es/space') ||
51
+            id.includes('node_modules/antd/es/spin') ||
52
+            id.includes('node_modules/antd/es/typography') ||
53
+            id.includes('node_modules/antd/es/config-provider') ||
54
+            id.includes('node_modules/antd/es/alert')
55
+          ) {
56
+            return 'antd-core';
57
+          }
58
+
59
+          // 表单和反馈组件(中频使用)
60
+          if (
61
+            id.includes('node_modules/antd/es/message') ||
62
+            id.includes('node_modules/antd/es/popconfirm') ||
63
+            id.includes('node_modules/antd/es/tooltip') ||
64
+            id.includes('node_modules/antd/es/select')
65
+          ) {
66
+            return 'antd-feedback';
67
+          }
68
+
69
+          // 布局和导航组件(中频使用)
70
+          if (
71
+            id.includes('node_modules/antd/es/drawer') ||
72
+            id.includes('node_modules/antd/es/list') ||
73
+            id.includes('node_modules/antd/es/card') ||
74
+            id.includes('node_modules/antd/es/divider') ||
75
+            id.includes('node_modules/antd/es/empty')
76
+          ) {
77
+            return 'antd-layout';
78
+          }
79
+
80
+          // 数据展示组件(低频使用,按需加载)
81
+          if (
82
+            id.includes('node_modules/antd/es/tree') ||
83
+            id.includes('node_modules/antd/es/table') ||
84
+            id.includes('node_modules/antd/es/dropdown')
85
+          ) {
86
+            return 'antd-data';
87
+          }
88
+
89
+          // 其他 Ant Design 代码(图标、样式、工具等)
40 90
           if (id.includes('node_modules/antd') || id.includes('node_modules/@ant-design')) {
41 91
             return 'antd-vendor';
42 92
           }
93
+
94
+          // ========== 文档处理库(按需加载)==========
95
+          if (
96
+            id.includes('node_modules/mammoth') ||
97
+            id.includes('node_modules/docx-preview')
98
+          ) {
99
+            return 'document-libs';
100
+          }
101
+
102
+          // ========== 导出功能库(按需加载)==========
103
+          if (
104
+            id.includes('node_modules/jspdf') ||
105
+            id.includes('node_modules/html2canvas')
106
+          ) {
107
+            return 'export-libs';
108
+          }
109
+
110
+          // ========== Markdown 处理库 ==========
111
+          if (
112
+            id.includes('node_modules/react-markdown') ||
113
+            id.includes('node_modules/remark-') ||
114
+            id.includes('node_modules/rehype-') ||
115
+            id.includes('node_modules/turndown') ||
116
+            id.includes('node_modules/unified') ||
117
+            id.includes('node_modules/micromark')
118
+          ) {
119
+            return 'markdown-vendor';
120
+          }
121
+
122
+          // ========== Slate 编辑器 ==========
43 123
           if (
44 124
             id.includes('node_modules/slate') ||
45 125
             id.includes('node_modules/slate-react') ||
@@ -47,6 +127,8 @@ export default defineConfig({
47 127
           ) {
48 128
             return 'slate-vendor';
49 129
           }
130
+
131
+          // ========== 工具库 ==========
50 132
           if (
51 133
             id.includes('node_modules/axios') ||
52 134
             id.includes('node_modules/zustand') ||
@@ -54,7 +136,8 @@ export default defineConfig({
54 136
           ) {
55 137
             return 'utils-vendor';
56 138
           }
57
-          // All other node_modules go into a generic vendor chunk
139
+
140
+          // 其他 node_modules
58 141
           if (id.includes('node_modules')) {
59 142
             return 'vendor';
60 143
           }
@@ -67,5 +150,35 @@ export default defineConfig({
67 150
         propertyReadSideEffects: false,
68 151
       },
69 152
     },
153
+
154
+    // 启用 CSS 代码分割
155
+    cssCodeSplit: true,
156
+
157
+    // 小于此阈值的资源将内联为 base64
158
+    assetsInlineLimit: 4096, // 4KB
159
+  },
160
+
161
+  // 开发服务器配置
162
+  server: {
163
+    port: 5173,
164
+    host: true,
165
+    open: false,
166
+  },
167
+
168
+  // 依赖预构建优化
169
+  optimizeDeps: {
170
+    include: [
171
+      'react',
172
+      'react-dom',
173
+      'axios',
174
+      'zustand',
175
+      'antd',
176
+      '@ant-design/icons',
177
+    ],
178
+    // 排除不需要预构建的大型依赖
179
+    exclude: [
180
+      'mammoth',
181
+      'docx-preview',
182
+    ],
70 183
   },
71 184
 });