Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions plugins/vite-plugin-dev-locale.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* 仅「开发(serve)」阶段生效:把各 locale/index.(ts|js) 中「非当前语言」的语言 import
* 就地替换为空对象,避免 dev 下每个 locale 目录都请求全部 5 种语言文件。
*
* 背景:i18n 用 import.meta.glob(eager) 加载全部 locale/index,每个 index 又静态
* "import xx from './<lang>'" 引入 5 种语言 → 一个目录 6 个请求,全站 700+。dev 实际只用
* 一种语言,其余是浪费。
*
* 转换示例(当前语言 = zh_CN):
* import zh_HK from './zh_HK'; => const zh_HK = {};
* import zh_CN from './zh_CN'; => (保留,真实加载)
* resources 对象仍引用这些标识符,结构不变,非当前语言为 {} 不会报错。
*
* 当前语言由 VITE_DEV_LOCALE(默认 zh_CN)在启动时决定;prod 不受影响(apply: 'serve')。
* 遇到非标准写法(如深层路径的语言 import)自动跳过,回退为全量加载,无副作用。
*/
const LANGS = ['zh_CN', 'en_US', 'zh_HK', 'ru_RU', 'ja_JP'];

export default function devSingleLocale(activeLocale: string) {
const active = LANGS.includes(activeLocale) ? activeLocale : 'zh_CN';
const importRe = /import\s+(\w+)\s+from\s+'\.\/(\w+)';/g;

return {
name: 'dev-single-locale',
enforce: 'pre' as const,
apply: 'serve' as const,
transform(code: string, id: string) {
const clean = id.split('?')[0];
if (!/\/(locale|locales)\/index\.(ts|js)$/.test(clean)) return null;
let changed = false;
const out = code.replace(importRe, (match, ident: string, lang: string) => {
if (LANGS.includes(lang) && lang !== active) {
changed = true;
return `const ${ident} = {};`;
}
return match;
});
if (!changed) return null;
return { code: out, map: null };
},
};
}
43 changes: 43 additions & 0 deletions plugins/vite-plugin-lazy-eager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* 仅在「生产构建」阶段,把用于优化 Vite dev 请求数的 `React.lazy(() => import('x'))`
* 还原为静态 `import`。
*
* 背景:dev 下 Vite 原生 ESM「一个模块一个请求」,路由/页面若全部静态 import 会在登录页
* 就拉起数千个模块。改为 React.lazy 后 dev 只按需加载。但生产已由 Rollup 打包,不存在
* 「多请求」问题,业务希望产物保持懒加载改造前的形态(无额外按需 chunk、无路由级 Suspense)。
Comment on lines +5 to +7
*
* 因此本插件只在 `vite build` 时生效(apply: 'build'),把下面两种写法转回静态 import:
* const X = React.lazy(() => import('spec'));
* -> import X from 'spec';
* const X = React.lazy(() => import('spec').then((m) => ({ default: m.Named })));
* -> import { Named as X } from 'spec';
*
* 仅作用于本次懒加载改造涉及的文件(各 entry.tsx、routers/index.tsx、App.tsx),
* 不影响代码库中其它本就希望在生产也保持懒加载的 React.lazy 用法。
*/
export default function lazyToEagerOnBuild() {
const shouldTransform = (id: string) => {
const clean = id.split('?')[0];
return clean.endsWith('/entry.tsx') || clean.endsWith('/routers/index.tsx') || clean.endsWith('/src/App.tsx');
};

// 具名导出:React.lazy(() => import('spec').then((m) => ({ default: m.Named })))
const namedRe =
/const\s+(\w+)\s*=\s*React\.lazy\(\s*\(\)\s*=>\s*import\(\s*(['"])(.+?)\2\s*\)\s*\.then\(\s*\(\s*m\s*\)\s*=>\s*\(\s*\{\s*default:\s*m\.(\w+)\s*\}\s*\)\s*\)\s*\)\s*;/g;
// 默认导出:React.lazy(() => import('spec'))
const defaultRe = /const\s+(\w+)\s*=\s*React\.lazy\(\s*\(\)\s*=>\s*import\(\s*(['"])(.+?)\2\s*\)\s*\)\s*;/g;

return {
name: 'lazy-to-eager-on-build',
enforce: 'pre' as const,
apply: 'build' as const,
transform(code: string, id: string) {
if (!shouldTransform(id) || !code.includes('React.lazy')) return null;
const out = code
.replace(namedRe, (_m, name, _q, spec, exported) => `import { ${exported} as ${name} } from '${spec}';`)
.replace(defaultRe, (_m, name, _q, spec) => `import ${name} from '${spec}';`);
if (out === code) return null;
return { code: out, map: null };
},
};
}
31 changes: 18 additions & 13 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ import 'antd/dist/antd.less';
import { useTranslation } from 'react-i18next';
import _ from 'lodash';

import TaskOutput from '@/pages/taskOutput';
import TaskHostOutput from '@/pages/taskOutput/host';
import { getAuthorizedDatasourceCates, Cate } from '@/components/AdvancedWrap';
import { GetProfile } from '@/services/account';
import { getBusiGroups, getDatasourceBriefList, getMenuPerm, getInstallDate } from '@/services/common';
Expand All @@ -36,7 +34,6 @@ import { getCleanBusinessGroupIds, getDefaultBusiness, getVaildBusinessGroup } f
import { IRawTimeRange } from '@/components/TimeRangePicker';
import { getN9eConfig } from '@/pages/siteSettings/services';
import { getDarkMode, updateDarkMode } from '@/utils/darkMode';
import SharedDetail from '@/pages/event/DetailNG/SharedDetail';
import { AiChatProvider, AiChatContainer } from '@/components/AiChatNG';
import HocRenderer from './components/HocRenderer';
import HeaderMenu from './components/SideMenu';
Expand All @@ -50,6 +47,12 @@ import CustomerServiceFloatButton from 'plus:/components/CustomerServiceFloatBut
import './App.less';
import './global.variable.less';

// 顶层路由组件懒加载:SharedDetail 会连带引入事件详情 + 全部数据源插件注册表(近千个模块),
// 只在 /share/alert-his-events 路由用到,改为懒加载后登录页等页面不再 eager 拉起这些依赖。
const TaskOutput = React.lazy(() => import('@/pages/taskOutput'));
const TaskHostOutput = React.lazy(() => import('@/pages/taskOutput/host'));
const SharedDetail = React.lazy(() => import('@/pages/event/DetailNG/SharedDetail'));

interface IProfile {
admin?: boolean;
nickname: string;
Expand Down Expand Up @@ -346,16 +349,18 @@ function App() {
}}
basename={basePrefix}
>
<Switch>
<Route exact path='/job-task/:busiId/output/:taskId/:outputType' component={TaskOutput} />
<Route exact path='/job-task/:busiId/output/:taskId/:host/:outputType' component={TaskHostOutput} />
<Route exact path='/share/alert-his-events/:eventId' component={SharedDetail} />
<>
{location.pathname !== `${basePrefix}/out-of-service` && <HeaderMenu />}
<Content />
<HocRenderer></HocRenderer>
</>
</Switch>
<React.Suspense fallback={<Spin spinning style={{ width: '100%', height: '100vh', display: 'flex', justifyContent: 'center', alignItems: 'center' }} />}>
<Switch>
<Route exact path='/job-task/:busiId/output/:taskId/:outputType' component={TaskOutput} />
<Route exact path='/job-task/:busiId/output/:taskId/:host/:outputType' component={TaskHostOutput} />
<Route exact path='/share/alert-his-events/:eventId' component={SharedDetail} />
<>
{location.pathname !== `${basePrefix}/out-of-service` && <HeaderMenu />}
<Content />
<HocRenderer></HocRenderer>
</>
</Switch>
</React.Suspense>
</Router>
</ConfigProvider>
</CommonStateContext.Provider>
Expand Down
6 changes: 6 additions & 0 deletions src/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ let language = 'zh_CN';
if (localStorageLanguage && _.includes(languages, localStorageLanguage)) {
language = localStorageLanguage;
}
// 开发环境仅加载单一语言(见 plugins/vite-plugin-dev-locale),此处需与之对齐,
// 否则运行时语言与已加载语言不一致会显示成翻译 key。可用 VITE_DEV_LOCALE 指定,默认 zh_CN。
if (import.meta.env.DEV) {
const devLocale = import.meta.env.VITE_DEV_LOCALE as string | undefined;
language = devLocale && _.includes(languages, devLocale) ? devLocale : 'zh_CN';
}

function getTranslations() {
const translations: any = import.meta.glob('../src/**/{locale,locales}/index.(ts|js)', { eager: true });
Expand Down
12 changes: 5 additions & 7 deletions src/pages/aiConfig/entry.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import React from 'react';

import { PATH as agentPath } from './agents/constants';
import AgentList from './agents/pages/List';

import { PATH as llmConfigPath } from './llmConfigs/constants';
import LLMConfigList from './llmConfigs/pages/List';

import { PATH as skillPath } from './skills/constants';
import SkillList from './skills/pages/List';

import { PATH as mcpServerPath } from './mcpServers/constants';
import MCPServerList from './mcpServers/pages/List';

const AgentList = React.lazy(() => import('./agents/pages/List'));
const LLMConfigList = React.lazy(() => import('./llmConfigs/pages/List'));
const SkillList = React.lazy(() => import('./skills/pages/List'));
const MCPServerList = React.lazy(() => import('./mcpServers/pages/List'));

export default {
routes: [
Expand Down
3 changes: 2 additions & 1 deletion src/pages/alertCurEvent/entry.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import React from 'react';

import { PATH } from './constants';
import List from './pages/List';
import './style.less';
import './locale';

const List = React.lazy(() => import('./pages/List'));

export default {
routes: [
{
Expand Down
8 changes: 5 additions & 3 deletions src/pages/builtInComponents/entry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@
* limitations under the License.
*
*/
import React from 'react';
import { pathname } from './constants';
import List from './List';
import AlertDetail from './AlertRules/Detail';
import DashboardDetail from './Dashboards/Detail';
import './locale';
import './style.less';

const List = React.lazy(() => import('./List'));
const AlertDetail = React.lazy(() => import('./AlertRules/Detail'));
const DashboardDetail = React.lazy(() => import('./Dashboards/Detail'));

export default {
routes: [
{
Expand Down
3 changes: 2 additions & 1 deletion src/pages/contacts/entry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import React from 'react';

import './locale';
import { NS } from './constants';
import List from './pages/List';

const List = React.lazy(() => import('./pages/List'));

export default {
routes: [
Expand Down
3 changes: 2 additions & 1 deletion src/pages/embeddedDashboards/entry.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React from 'react';
import Audits from './index';
import './style.less';
import './locale';

const Audits = React.lazy(() => import('./index'));

export default {
routes: [
{
Expand Down
5 changes: 3 additions & 2 deletions src/pages/embeddedProduct/entry.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import React from 'react';

import { PATH, DETAIL_PATH } from './constants';
import List from './pages/List';
import Detail from './pages/Detail';
import './locale';

const List = React.lazy(() => import('./pages/List'));
const Detail = React.lazy(() => import('./pages/Detail'));

export default {
routes: [
{
Expand Down
9 changes: 5 additions & 4 deletions src/pages/eventPipeline/entry.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import React from 'react';
import { NS } from './constants';
import List from './pages/ListWithPageLayout';
import Edit from './pages/EditWithPageLayout';
import Executions from './pages/Executions';
import ExecutionDetail from './pages/Executions/DetailWithPageLayout';

import './locale';

const List = React.lazy(() => import('./pages/ListWithPageLayout'));
const Edit = React.lazy(() => import('./pages/EditWithPageLayout'));
const Executions = React.lazy(() => import('./pages/Executions'));
const ExecutionDetail = React.lazy(() => import('./pages/Executions/DetailWithPageLayout'));

export default {
routes: [
{
Expand Down
3 changes: 2 additions & 1 deletion src/pages/hosts/entry.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import React from 'react';
import { PATH } from './constants';
import List from './pages/List';

import './style.less';
import './locale';

const List = React.lazy(() => import('./pages/List'));

export default {
routes: [
{
Expand Down
6 changes: 5 additions & 1 deletion src/pages/logExplorer/entry.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import React from 'react';
import { PATHNAME } from './constants';
import Index from './index';

import './locale';

import './style.less';

// 页面本体懒加载:entry 会被 import.meta.glob({ eager: true }) 在启动时同步加载,
// 若直接静态 import ./index 会把整棵页面树(含数据源插件)在登录页就拉起。
const Index = React.lazy(() => import('./index'));

export default {
routes: [
{
Expand Down
3 changes: 2 additions & 1 deletion src/pages/metricsBuiltin/entry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@
*/
import React from 'react';
import { pathname } from './constants';
import List from './List';
import './locale';
import './style.less';

const List = React.lazy(() => import('./List'));

export default {
routes: [
{
Expand Down
7 changes: 4 additions & 3 deletions src/pages/notificationChannels/entry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import React from 'react';

import './locale';
import { NS } from './constants';
import ListNG from './pages/ListNG';
import Add from './pages/Add';
import Edit from './pages/Edit';

const ListNG = React.lazy(() => import('./pages/ListNG'));
const Add = React.lazy(() => import('./pages/Add'));
const Edit = React.lazy(() => import('./pages/Edit'));

export default {
routes: [
Expand Down
9 changes: 5 additions & 4 deletions src/pages/notificationRules/entry.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import React from 'react';

import { NS } from './constants';
import List from './pages/List';
import Add from './pages/Add';
import Edit from './pages/Edit';
import Detail from './pages/Detail';
import './style.less';
import './locale';

const List = React.lazy(() => import('./pages/List'));
const Add = React.lazy(() => import('./pages/Add'));
const Edit = React.lazy(() => import('./pages/Edit'));
const Detail = React.lazy(() => import('./pages/Detail'));

export default {
routes: [
{
Expand Down
3 changes: 2 additions & 1 deletion src/pages/notificationTemplates/entry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import React from 'react';

import './locale';
import { NS } from './constants';
import List from './pages/List';

const List = React.lazy(() => import('./pages/List'));

export default {
routes: [
Expand Down
Loading