wsj
3 days ago d26274d89d377067c1e2648192cffbf89464b361
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import { fileURLToPath, URL } from 'node:url';
import react from '@vitejs/plugin-react';
import { defineConfig, loadEnv } from 'vite';
 
/**
 * 布局、登录等入口页面会用到的 antd 组件。
 * 这些模块首屏必载,单独放进 antd chunk 以稳定缓存;
 * 表格、日期选择等只在业务页面使用的组件则交给 Rollup 按需分包。
 *
 * 注意:不要匹配 `antd/es/index.js`(`from 'antd'` 的 barrel 文件)。
 * manualChunks 会把 chunk 当成入口保留全部导出,barrel 进手动 chunk 后
 * 会把所有 antd 组件都拉进首屏(约 1.3MB),失去按需分包的意义。
 */
const ANTD_CORE_DIRS = [
  '_util',
  'app',
  'avatar',
  'breadcrumb',
  'button',
  'config-provider',
  'dropdown',
  'form',
  'input',
  'layout',
  'locale',
  'menu',
  'message',
  'modal',
  'notification',
  'space',
  'spin',
  'style',
  'tag',
  'theme',
  'tooltip',
  'version',
  'wave',
].join('|');
 
/** 第三方依赖拆包规则,页面本身通过路由懒加载按需加载。 */
const resolveVendorChunk = (id: string): string | undefined => {
  if (!id.includes('node_modules')) return undefined;
 
  const path = id.replace(/\\/g, '/');
 
  // 图标与 antd 互相引用,放在同一个 chunk,避免循环依赖。
  if (
    new RegExp(
      `\\/node_modules\\/(antd\\/es\\/(${ANTD_CORE_DIRS})\\/|@ant-design\\/(cssinjs|cssinjs-utils|colors|fast-color|icons|icons-svg)\\/)`,
    ).test(path)
  ) {
    return 'antd';
  }
 
  if (
    /\/node_modules\/(react|react-dom|scheduler|react-router|react-router-dom|@remix-run\/[^/]+)\//.test(
      path,
    )
  ) {
    return 'react';
  }
 
  if (/\/node_modules\/(axios|zustand|dayjs)\//.test(path)) {
    return 'vendor';
  }
 
  return undefined;
};
 
/** 开发环境通过 Vite 代理访问后端,避免浏览器跨域。 */
export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd(), '');
  const proxyTarget =
    env.VITE_API_PROXY_TARGET || env.VITE_API_BASE_URL || 'http://localhost:9090';
 
  return {
    plugins: [react()],
    resolve: {
      alias: {
        '@': fileURLToPath(new URL('./src', import.meta.url)),
      },
    },
    server: {
      port: 5173,
      host: true,
      proxy: {
        '/proxy-api': {
          target: proxyTarget,
          changeOrigin: true,
          rewrite: (path) => path.replace(/^\/proxy-api/, ''),
        },
      },
    },
    build: {
      // 首屏 chunk 已控制在 600KB 以内;按需加载的 ProComponents 业务包约 830KB。
      chunkSizeWarningLimit: 900,
      rollupOptions: {
        output: {
          manualChunks: resolveVendorChunk,
        },
      },
    },
  };
});