@lark-apaas/fullstack-rspack-preset 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +13 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +5 -0
- package/lib/module-alias/clsx.d.ts +2 -0
- package/lib/module-alias/clsx.js +12 -0
- package/lib/module-alias/echartThemeUD.json +148 -0
- package/lib/module-alias/echarts.d.ts +4 -0
- package/lib/module-alias/echarts.js +57 -0
- package/lib/preset.d.ts +10 -0
- package/lib/preset.js +305 -0
- package/lib/rspack-plugins/route-parser-plugin.d.ts +20 -0
- package/lib/rspack-plugins/route-parser-plugin.js +269 -0
- package/lib/rspack-plugins/slardar-performance-monitor-plugin.d.ts +10 -0
- package/lib/rspack-plugins/slardar-performance-monitor-plugin.js +86 -0
- package/lib/utils/dev-server-listener.d.ts +5 -0
- package/lib/utils/dev-server-listener.js +113 -0
- package/package.json +44 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Lark Technologies Pte. Ltd. and/or its affiliates
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted,provided that the above copyright notice and this permission notice appear in all copies.
|
|
6
|
+
|
|
7
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
|
8
|
+
IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
|
|
9
|
+
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
|
|
10
|
+
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
|
|
11
|
+
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
|
12
|
+
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
|
13
|
+
ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
package/lib/index.d.ts
ADDED
package/lib/index.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createRecommendRspackConfig = void 0;
|
|
4
|
+
var preset_1 = require("./preset");
|
|
5
|
+
Object.defineProperty(exports, "createRecommendRspackConfig", { enumerable: true, get: function () { return preset_1.createRecommendRspackConfig; } });
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.clsx = clsx;
|
|
7
|
+
const clsx_1 = __importDefault(require("clsx"));
|
|
8
|
+
const tailwind_merge_1 = require("tailwind-merge");
|
|
9
|
+
function clsx(...args) {
|
|
10
|
+
return (0, tailwind_merge_1.twMerge)((0, clsx_1.default)(...args));
|
|
11
|
+
}
|
|
12
|
+
exports.default = clsx;
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"themeName": "UD Theme Style",
|
|
4
|
+
"theme": {
|
|
5
|
+
"seriesCnt": "6",
|
|
6
|
+
"backgroundColor": "rgba(0,0,0,0)",
|
|
7
|
+
"titleColor": "#1f2329",
|
|
8
|
+
"subtitleColor": "#8f959e",
|
|
9
|
+
"textColorShow": false,
|
|
10
|
+
"textColor": "#333",
|
|
11
|
+
"markTextColor": "#ffffff",
|
|
12
|
+
"color": [
|
|
13
|
+
"#3370eb",
|
|
14
|
+
"#1bcebf",
|
|
15
|
+
"#ffc60a",
|
|
16
|
+
"#ed6d0c",
|
|
17
|
+
"#dca1e4",
|
|
18
|
+
"#25b2e5",
|
|
19
|
+
"#6dcdeb",
|
|
20
|
+
"#288fcb",
|
|
21
|
+
"#94b5f5",
|
|
22
|
+
"#8f61d1",
|
|
23
|
+
"#8f61d1",
|
|
24
|
+
"#bf78e9",
|
|
25
|
+
"#008280",
|
|
26
|
+
"#27ad8e",
|
|
27
|
+
"#7bc335"
|
|
28
|
+
],
|
|
29
|
+
"borderColor": "#dee0e3",
|
|
30
|
+
"borderWidth": 0,
|
|
31
|
+
"visualMapColor": ["#25b2e5", "#6dcdeb", "#288fcb"],
|
|
32
|
+
"legendTextColor": "#8f959e",
|
|
33
|
+
"kColor": "#fdc6c4",
|
|
34
|
+
"kColor0": "transparent",
|
|
35
|
+
"kBorderColor": "#f54a45",
|
|
36
|
+
"kBorderColor0": "#32a645",
|
|
37
|
+
"kBorderWidth": "2",
|
|
38
|
+
"lineWidth": "1",
|
|
39
|
+
"symbolSize": "6",
|
|
40
|
+
"symbol": "emptyCircle",
|
|
41
|
+
"symbolBorderWidth": "1",
|
|
42
|
+
"lineSmooth": true,
|
|
43
|
+
"graphLineWidth": 1,
|
|
44
|
+
"graphLineColor": "#dee0e3",
|
|
45
|
+
"mapLabelColor": "#000",
|
|
46
|
+
"mapLabelColorE": "#516b91",
|
|
47
|
+
"mapBorderColor": "#516b91",
|
|
48
|
+
"mapBorderColorE": "#516b91",
|
|
49
|
+
"mapBorderWidth": 0.5,
|
|
50
|
+
"mapBorderWidthE": 1,
|
|
51
|
+
"mapAreaColor": "#f3f3f3",
|
|
52
|
+
"mapAreaColorE": "#a5e7f0",
|
|
53
|
+
"axes": [
|
|
54
|
+
{
|
|
55
|
+
"type": "all",
|
|
56
|
+
"name": "通用坐标轴",
|
|
57
|
+
"axisLineShow": true,
|
|
58
|
+
"axisLineColor": "#dee0e3",
|
|
59
|
+
"axisTickShow": false,
|
|
60
|
+
"axisTickColor": "#333",
|
|
61
|
+
"axisLabelShow": true,
|
|
62
|
+
"axisLabelColor": "#8f959e",
|
|
63
|
+
"splitLineShow": true,
|
|
64
|
+
"splitLineColor": ["#dee0e3"],
|
|
65
|
+
"splitAreaShow": false,
|
|
66
|
+
"splitAreaColor": ["rgba(250,250,250,0.05)", "rgba(200,200,200,0.02)"]
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"type": "category",
|
|
70
|
+
"name": "类目坐标轴",
|
|
71
|
+
"axisLineShow": true,
|
|
72
|
+
"axisLineColor": "#333",
|
|
73
|
+
"axisTickShow": true,
|
|
74
|
+
"axisTickColor": "#333",
|
|
75
|
+
"axisLabelShow": true,
|
|
76
|
+
"axisLabelColor": "#333",
|
|
77
|
+
"splitLineShow": false,
|
|
78
|
+
"splitLineColor": ["#ccc"],
|
|
79
|
+
"splitAreaShow": false,
|
|
80
|
+
"splitAreaColor": ["rgba(250,250,250,0.3)", "rgba(200,200,200,0.3)"]
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"type": "value",
|
|
84
|
+
"name": "数值坐标轴",
|
|
85
|
+
"axisLineShow": true,
|
|
86
|
+
"axisLineColor": "#333",
|
|
87
|
+
"axisTickShow": true,
|
|
88
|
+
"axisTickColor": "#333",
|
|
89
|
+
"axisLabelShow": true,
|
|
90
|
+
"axisLabelColor": "#333",
|
|
91
|
+
"splitLineShow": true,
|
|
92
|
+
"splitLineColor": ["#ccc"],
|
|
93
|
+
"splitAreaShow": false,
|
|
94
|
+
"splitAreaColor": ["rgba(250,250,250,0.3)", "rgba(200,200,200,0.3)"]
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"type": "log",
|
|
98
|
+
"name": "对数坐标轴",
|
|
99
|
+
"axisLineShow": true,
|
|
100
|
+
"axisLineColor": "#333",
|
|
101
|
+
"axisTickShow": true,
|
|
102
|
+
"axisTickColor": "#333",
|
|
103
|
+
"axisLabelShow": true,
|
|
104
|
+
"axisLabelColor": "#333",
|
|
105
|
+
"splitLineShow": true,
|
|
106
|
+
"splitLineColor": ["#ccc"],
|
|
107
|
+
"splitAreaShow": false,
|
|
108
|
+
"splitAreaColor": ["rgba(250,250,250,0.3)", "rgba(200,200,200,0.3)"]
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"type": "time",
|
|
112
|
+
"name": "时间坐标轴",
|
|
113
|
+
"axisLineShow": true,
|
|
114
|
+
"axisLineColor": "#333",
|
|
115
|
+
"axisTickShow": true,
|
|
116
|
+
"axisTickColor": "#333",
|
|
117
|
+
"axisLabelShow": true,
|
|
118
|
+
"axisLabelColor": "#333",
|
|
119
|
+
"splitLineShow": true,
|
|
120
|
+
"splitLineColor": ["#ccc"],
|
|
121
|
+
"splitAreaShow": false,
|
|
122
|
+
"splitAreaColor": ["rgba(250,250,250,0.3)", "rgba(200,200,200,0.3)"]
|
|
123
|
+
}
|
|
124
|
+
],
|
|
125
|
+
"axisSeperateSetting": false,
|
|
126
|
+
"toolboxColor": "#8f959e",
|
|
127
|
+
"toolboxEmphasisColor": "#1f2329",
|
|
128
|
+
"tooltipAxisColor": "#dee0e3",
|
|
129
|
+
"tooltipAxisWidth": 1,
|
|
130
|
+
"timelineLineColor": "#336df4",
|
|
131
|
+
"timelineLineWidth": "-1",
|
|
132
|
+
"timelineItemColor": "#336df4",
|
|
133
|
+
"timelineItemColorE": "#1456f0",
|
|
134
|
+
"timelineCheckColor": "#1456f0",
|
|
135
|
+
"timelineCheckBorderColor": "#94b4ff",
|
|
136
|
+
"timelineItemBorderWidth": "0.5",
|
|
137
|
+
"timelineControlColor": "#336df4",
|
|
138
|
+
"timelineControlBorderColor": "#336df4",
|
|
139
|
+
"timelineControlBorderWidth": 0.5,
|
|
140
|
+
"timelineLabelColor": "#8f959e",
|
|
141
|
+
"datazoomBackgroundColor": "rgba(0,0,0,0)",
|
|
142
|
+
"datazoomDataColor": "rgba(255,255,255,0.3)",
|
|
143
|
+
"datazoomFillColor": "rgba(167,183,204,0.4)",
|
|
144
|
+
"datazoomHandleColor": "#a7b7cc",
|
|
145
|
+
"datazoomHandleWidth": "100",
|
|
146
|
+
"datazoomLabelColor": "#333"
|
|
147
|
+
}
|
|
148
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.echarts = void 0;
|
|
40
|
+
exports.resgisterEchartsTheme = resgisterEchartsTheme;
|
|
41
|
+
const echartsModule = __importStar(require("echarts"));
|
|
42
|
+
var echarts_1 = require("echarts");
|
|
43
|
+
Object.defineProperty(exports, "echarts", { enumerable: true, get: function () { return __importDefault(echarts_1).default; } });
|
|
44
|
+
exports.default = echartsModule;
|
|
45
|
+
const echarts_2 = require("echarts");
|
|
46
|
+
const echartThemeUD_json_1 = __importDefault(require("./echartThemeUD.json"));
|
|
47
|
+
let isRegistered = false;
|
|
48
|
+
function resgisterEchartsTheme() {
|
|
49
|
+
// 注册 ud 主题,全局仅注册一次
|
|
50
|
+
if (isRegistered) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
isRegistered = true;
|
|
54
|
+
(0, echarts_2.registerTheme)('ud', echartThemeUD_json_1.default.theme);
|
|
55
|
+
}
|
|
56
|
+
resgisterEchartsTheme();
|
|
57
|
+
// registerChinaMap();
|
package/lib/preset.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type Configuration } from '@rspack/core';
|
|
2
|
+
export interface CreateRecommendRspackConfigOptions {
|
|
3
|
+
isDev?: boolean;
|
|
4
|
+
/** 是否需要插件解析路由 */
|
|
5
|
+
needRoutes?: boolean;
|
|
6
|
+
/** 客户端基础路径 */
|
|
7
|
+
clientBasePath?: string;
|
|
8
|
+
publicPath?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function createRecommendRspackConfig(options: CreateRecommendRspackConfigOptions): Configuration;
|
package/lib/preset.js
ADDED
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createRecommendRspackConfig = createRecommendRspackConfig;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const core_1 = __importDefault(require("@rspack/core"));
|
|
9
|
+
const devtool_kits_1 = require("@lark-apaas/devtool-kits");
|
|
10
|
+
const dev_server_listener_1 = require("./utils/dev-server-listener");
|
|
11
|
+
const route_parser_plugin_1 = __importDefault(require("./rspack-plugins/route-parser-plugin"));
|
|
12
|
+
const slardar_performance_monitor_plugin_1 = __importDefault(require("./rspack-plugins/slardar-performance-monitor-plugin"));
|
|
13
|
+
function createRecommendRspackConfig(options) {
|
|
14
|
+
const { isDev = true, needRoutes = true, clientBasePath = '', publicPath = '', // 静态资源路径
|
|
15
|
+
} = options;
|
|
16
|
+
const rootDir = process.cwd();
|
|
17
|
+
const serverPort = process.env.SERVER_PORT || '3000';
|
|
18
|
+
return {
|
|
19
|
+
cache: false,
|
|
20
|
+
experiments: {
|
|
21
|
+
css: true,
|
|
22
|
+
},
|
|
23
|
+
resolve: {
|
|
24
|
+
mainFields: ['module', 'browser', 'main'],
|
|
25
|
+
extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'],
|
|
26
|
+
},
|
|
27
|
+
module: {
|
|
28
|
+
rules: [
|
|
29
|
+
{
|
|
30
|
+
test: /\.svg$/,
|
|
31
|
+
type: 'asset',
|
|
32
|
+
parser: {
|
|
33
|
+
dataUrlCondition: {
|
|
34
|
+
maxSize: 10 * 1024, // 对应vite的assetsInlineLimit
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
test: /\.(png|jpe?g|gif|webp|ico)$/,
|
|
40
|
+
type: 'asset',
|
|
41
|
+
parser: {
|
|
42
|
+
dataUrlCondition: {
|
|
43
|
+
maxSize: 10 * 1024, // 对应vite的assetsInlineLimit
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
test: /\.css$/,
|
|
49
|
+
use: [
|
|
50
|
+
{
|
|
51
|
+
loader: 'postcss-loader',
|
|
52
|
+
options: {
|
|
53
|
+
postcssOptions: {
|
|
54
|
+
plugins: [
|
|
55
|
+
[
|
|
56
|
+
'postcss-import',
|
|
57
|
+
{
|
|
58
|
+
resolve: (id, _basedir) => {
|
|
59
|
+
// 只有dev环境需要打包选中精调所需的一些预置样式, prod环境则不打包
|
|
60
|
+
if (id === '@/inspector.dev.css') {
|
|
61
|
+
return isDev
|
|
62
|
+
? path_1.default.join(_basedir, '/inspector.dev.css')
|
|
63
|
+
: [];
|
|
64
|
+
}
|
|
65
|
+
return id;
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
],
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
type: 'css',
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
test: /\.tsx?$/,
|
|
78
|
+
use: [
|
|
79
|
+
{
|
|
80
|
+
loader: 'builtin:swc-loader',
|
|
81
|
+
options: {
|
|
82
|
+
/**
|
|
83
|
+
* @type {import('@swc/core').JscConfig}
|
|
84
|
+
*/
|
|
85
|
+
jsc: {
|
|
86
|
+
parser: {
|
|
87
|
+
syntax: 'typescript',
|
|
88
|
+
jsx: true,
|
|
89
|
+
},
|
|
90
|
+
transform: {
|
|
91
|
+
react: {
|
|
92
|
+
runtime: 'automatic',
|
|
93
|
+
...(isDev
|
|
94
|
+
? {
|
|
95
|
+
importSource: path_1.default.dirname(require.resolve('@lark-apaas/miaoda-inspector-jsx-runtime')),
|
|
96
|
+
}
|
|
97
|
+
: {}),
|
|
98
|
+
development: isDev,
|
|
99
|
+
refresh: isDev,
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
...(isDev
|
|
106
|
+
? [require.resolve('@lark-apaas/miaoda-inspector-babel-plugin')]
|
|
107
|
+
: []),
|
|
108
|
+
],
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
},
|
|
112
|
+
plugins: [
|
|
113
|
+
// 针对 clsx/echarts 等包,让其默认好用
|
|
114
|
+
new core_1.default.NormalModuleReplacementPlugin(/^(clsx|echarts)$/, function (resource) {
|
|
115
|
+
if (!resource.context.endsWith('module-alias')) {
|
|
116
|
+
if (resource.request.endsWith('echarts')) {
|
|
117
|
+
resource.request = require.resolve('./module-alias/echarts');
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
resource.request = require.resolve('./module-alias/clsx');
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}),
|
|
124
|
+
new core_1.default.DefinePlugin({
|
|
125
|
+
'process.env.NODE_ENV': JSON.stringify(isDev ? 'development' : 'production'),
|
|
126
|
+
'process.env.runtimeMode': 'fullstack',
|
|
127
|
+
'process.env.CLIENT_BASE_PATH': JSON.stringify(clientBasePath),
|
|
128
|
+
// FIXME:安全漏洞,会读取到服务路径,不应该在客户端代码中使用
|
|
129
|
+
'process.env.CWD': JSON.stringify(process.cwd()),
|
|
130
|
+
// 解决 window 未定义问题
|
|
131
|
+
'typeof window': JSON.stringify('object'),
|
|
132
|
+
window: 'globalThis',
|
|
133
|
+
}),
|
|
134
|
+
new core_1.default.HotModuleReplacementPlugin(),
|
|
135
|
+
// 编译相关,静态资源复制到输出目录
|
|
136
|
+
new core_1.default.CopyRspackPlugin({
|
|
137
|
+
patterns: [
|
|
138
|
+
{
|
|
139
|
+
from: path_1.default.resolve(rootDir, "./client/public"),
|
|
140
|
+
to: path_1.default.resolve(rootDir, "dist/client"), // 输出目录
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
}),
|
|
144
|
+
// 性能监控插件
|
|
145
|
+
new slardar_performance_monitor_plugin_1.default(),
|
|
146
|
+
// 开发环境下,解析路由
|
|
147
|
+
isDev && needRoutes &&
|
|
148
|
+
new route_parser_plugin_1.default({
|
|
149
|
+
appPath: './client/src/app.tsx',
|
|
150
|
+
outputPath: path_1.default.resolve(rootDir, 'dist/client/routes.json'),
|
|
151
|
+
}),
|
|
152
|
+
],
|
|
153
|
+
optimization: isDev
|
|
154
|
+
? {}
|
|
155
|
+
: {
|
|
156
|
+
moduleIds: 'deterministic',
|
|
157
|
+
concatenateModules: true,
|
|
158
|
+
minimize: true, // 对应vite的minify配置
|
|
159
|
+
minimizer: [
|
|
160
|
+
new core_1.default.SwcJsMinimizerRspackPlugin({
|
|
161
|
+
minimizerOptions: {
|
|
162
|
+
// 保持不压缩
|
|
163
|
+
minify: !isDev,
|
|
164
|
+
mangle: !isDev,
|
|
165
|
+
format: {
|
|
166
|
+
beautify: isDev,
|
|
167
|
+
comments: false,
|
|
168
|
+
},
|
|
169
|
+
compress: {
|
|
170
|
+
keep_classnames: true,
|
|
171
|
+
keep_fnames: true,
|
|
172
|
+
keep_fargs: !isDev,
|
|
173
|
+
unused: true,
|
|
174
|
+
dead_code: true,
|
|
175
|
+
drop_debugger: true,
|
|
176
|
+
// FIXME: 先临时开始 console.log
|
|
177
|
+
// drop_console: !isDev,
|
|
178
|
+
const_to_let: !isDev,
|
|
179
|
+
booleans_as_integers: !isDev,
|
|
180
|
+
booleans: !isDev,
|
|
181
|
+
// maybe unsafe
|
|
182
|
+
reduce_funcs: !isDev,
|
|
183
|
+
reduce_vars: !isDev,
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
}),
|
|
187
|
+
new core_1.default.LightningCssMinimizerRspackPlugin(),
|
|
188
|
+
],
|
|
189
|
+
sideEffects: true,
|
|
190
|
+
usedExports: true,
|
|
191
|
+
innerGraph: true,
|
|
192
|
+
providedExports: true,
|
|
193
|
+
mergeDuplicateChunks: true,
|
|
194
|
+
splitChunks: false, // 禁用代码分割,保持单文件输出
|
|
195
|
+
},
|
|
196
|
+
devtool: isDev ? 'source-map' : false, // 对应vite的sourcemap配置
|
|
197
|
+
devServer: {
|
|
198
|
+
port: process.env.CLIENT_DEV_PORT || 8080,
|
|
199
|
+
host: process.env.CLIENT_DEV_HOST || 'localhost',
|
|
200
|
+
allowedHosts: 'all',
|
|
201
|
+
hot: true,
|
|
202
|
+
liveReload: true,
|
|
203
|
+
historyApiFallback: true,
|
|
204
|
+
watchFiles: [{
|
|
205
|
+
paths: [path_1.default.resolve(rootDir, 'client/src/api/**/*')],
|
|
206
|
+
options: {
|
|
207
|
+
usePolling: true,
|
|
208
|
+
interval: 500,
|
|
209
|
+
},
|
|
210
|
+
}],
|
|
211
|
+
static: {
|
|
212
|
+
directory: path_1.default.resolve(rootDir, 'client/public'),
|
|
213
|
+
publicPath: publicPath,
|
|
214
|
+
},
|
|
215
|
+
webSocketServer: {
|
|
216
|
+
type: 'sockjs',
|
|
217
|
+
options: {
|
|
218
|
+
path: `${clientBasePath}/ws`,
|
|
219
|
+
},
|
|
220
|
+
},
|
|
221
|
+
client: {
|
|
222
|
+
webSocketTransport: 'sockjs',
|
|
223
|
+
webSocketURL: {
|
|
224
|
+
port: 0,
|
|
225
|
+
pathname: `${clientBasePath}/ws`
|
|
226
|
+
},
|
|
227
|
+
overlay: {
|
|
228
|
+
errors: false,
|
|
229
|
+
warnings: false,
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
headers: (req) => {
|
|
233
|
+
// 获取请求的Origin头
|
|
234
|
+
const requestOrigin = req.headers.origin ?? '';
|
|
235
|
+
// 定义允许的域名白名单
|
|
236
|
+
const allowedOrigins = [
|
|
237
|
+
'https://miaoda.feishu.cn',
|
|
238
|
+
'https://miaoda.feishu-boe.cn',
|
|
239
|
+
'https://miaoda.feishu-pre.cn',
|
|
240
|
+
];
|
|
241
|
+
// 检查请求的Origin是否在允许的列表中
|
|
242
|
+
const allowedOrigin = allowedOrigins.includes(requestOrigin)
|
|
243
|
+
? requestOrigin
|
|
244
|
+
: allowedOrigins[0]; // 默认返回第一个允许的域名
|
|
245
|
+
return {
|
|
246
|
+
'Access-Control-Allow-Origin': allowedOrigin,
|
|
247
|
+
};
|
|
248
|
+
},
|
|
249
|
+
onListening(server) {
|
|
250
|
+
(0, dev_server_listener_1.listenHmrTiming)(server);
|
|
251
|
+
},
|
|
252
|
+
proxy: [
|
|
253
|
+
{
|
|
254
|
+
context: [`${clientBasePath}/api`],
|
|
255
|
+
target: `http://localhost:${serverPort}`,
|
|
256
|
+
changeOrigin: true,
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
context: (pathname, req) => {
|
|
260
|
+
// 代理所有请求 HTML 响应的请求(页面路由)
|
|
261
|
+
const devServerWhiteList = ['/__rspack_hmr', '/webpack-dev-server', '.hot-update.json', '/dev/'];
|
|
262
|
+
const isHtmlRequest = req.headers.accept?.includes('text/html');
|
|
263
|
+
const isDevServerPath = devServerWhiteList.some((item) => pathname.includes(item));
|
|
264
|
+
return isHtmlRequest && !isDevServerPath;
|
|
265
|
+
},
|
|
266
|
+
target: `http://localhost:${serverPort}`,
|
|
267
|
+
changeOrigin: true,
|
|
268
|
+
logLevel: 'debug',
|
|
269
|
+
onError: (err, req, res) => (0, devtool_kits_1.handleDevProxyError)(err, req, res, {
|
|
270
|
+
logDir: process.env.LOG_DIR || './logs',
|
|
271
|
+
logFileName: 'server.std.log',
|
|
272
|
+
maxErrorLogs: 100,
|
|
273
|
+
}),
|
|
274
|
+
},
|
|
275
|
+
],
|
|
276
|
+
devMiddleware: {
|
|
277
|
+
index: false,
|
|
278
|
+
writeToDisk: (filePath) => filePath.endsWith('.html'),
|
|
279
|
+
},
|
|
280
|
+
setupMiddlewares: (middlewares, devServer) => {
|
|
281
|
+
if (devServer.app) {
|
|
282
|
+
(0, devtool_kits_1.registerMiddlewares)(devServer.app, [
|
|
283
|
+
(0, devtool_kits_1.createDevLogsMiddleware)({ logDir: process.env.LOG_DIR || './logs' }),
|
|
284
|
+
(0, devtool_kits_1.createOpenapiMiddleware)({
|
|
285
|
+
openapiFilePath: path_1.default.resolve(rootDir, './client/src/api/gen/openapi.json'),
|
|
286
|
+
serverDir: path_1.default.resolve(rootDir, './server'),
|
|
287
|
+
enableEnhancement: true,
|
|
288
|
+
}),
|
|
289
|
+
(0, devtool_kits_1.createCollectLogsMiddleware)({ logDir: process.env.LOG_DIR || './logs', fileName: 'browser.log' }),
|
|
290
|
+
], {
|
|
291
|
+
basePath: clientBasePath,
|
|
292
|
+
isDev
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
return middlewares;
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
output: {
|
|
299
|
+
publicPath,
|
|
300
|
+
path: path_1.default.resolve(rootDir, 'dist/client'),
|
|
301
|
+
clean: true,
|
|
302
|
+
globalObject: 'this',
|
|
303
|
+
},
|
|
304
|
+
};
|
|
305
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
interface RouteParserPluginOptions {
|
|
2
|
+
appPath?: string;
|
|
3
|
+
outputPath?: string;
|
|
4
|
+
}
|
|
5
|
+
declare class RouteParserPlugin {
|
|
6
|
+
private options;
|
|
7
|
+
private lastAppPathHash;
|
|
8
|
+
private cachedRoutes;
|
|
9
|
+
constructor(options?: RouteParserPluginOptions);
|
|
10
|
+
private log;
|
|
11
|
+
apply(compiler: any): void;
|
|
12
|
+
private shouldRegenerateRoutes;
|
|
13
|
+
private calculateFileHash;
|
|
14
|
+
private parseRoutes;
|
|
15
|
+
private isRouteComponent;
|
|
16
|
+
private extractRouteInfo;
|
|
17
|
+
private buildFullPath;
|
|
18
|
+
private evaluateTemplateLiteral;
|
|
19
|
+
}
|
|
20
|
+
export default RouteParserPlugin;
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
const fs = __importStar(require("fs"));
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
const crypto = __importStar(require("crypto"));
|
|
42
|
+
const parser_1 = require("@babel/parser");
|
|
43
|
+
const traverse_1 = __importDefault(require("@babel/traverse"));
|
|
44
|
+
const t = __importStar(require("@babel/types"));
|
|
45
|
+
class RouteParserPlugin {
|
|
46
|
+
constructor(options = {}) {
|
|
47
|
+
this.lastAppPathHash = null;
|
|
48
|
+
this.cachedRoutes = null;
|
|
49
|
+
this.options = {
|
|
50
|
+
appPath: options.appPath || './client/src/app.tsx',
|
|
51
|
+
outputPath: options.outputPath || './dist/client/routes.json',
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
log(level, message, ...args) {
|
|
55
|
+
const prefix = '[route-parser]';
|
|
56
|
+
const logMessage = `${prefix} ${message}`;
|
|
57
|
+
switch (level) {
|
|
58
|
+
case 'log':
|
|
59
|
+
console.log(logMessage, ...args);
|
|
60
|
+
break;
|
|
61
|
+
case 'warn':
|
|
62
|
+
console.warn(logMessage, ...args);
|
|
63
|
+
break;
|
|
64
|
+
case 'error':
|
|
65
|
+
console.error(logMessage, ...args);
|
|
66
|
+
break;
|
|
67
|
+
case 'info':
|
|
68
|
+
console.info(logMessage, ...args);
|
|
69
|
+
break;
|
|
70
|
+
default:
|
|
71
|
+
console.log(logMessage, ...args);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
apply(compiler) {
|
|
75
|
+
const pluginName = 'RouteParserPlugin';
|
|
76
|
+
compiler.hooks.emit.tapAsync(pluginName, (compilation, callback) => {
|
|
77
|
+
try {
|
|
78
|
+
if (this.shouldRegenerateRoutes()) {
|
|
79
|
+
const routes = this.parseRoutes();
|
|
80
|
+
this.cachedRoutes = routes;
|
|
81
|
+
}
|
|
82
|
+
const routesJson = JSON.stringify(this.cachedRoutes, null, 2);
|
|
83
|
+
compilation.assets['routes.json'] = {
|
|
84
|
+
source: () => routesJson,
|
|
85
|
+
size: () => routesJson.length
|
|
86
|
+
};
|
|
87
|
+
callback();
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
this.log('warn', '⚠️ 路由解析失败,使用默认路由:', error.message);
|
|
91
|
+
const defaultRoutes = [{ path: '/' }];
|
|
92
|
+
const routesJson = JSON.stringify(defaultRoutes, null, 2);
|
|
93
|
+
compilation.assets['routes.json'] = {
|
|
94
|
+
source: () => routesJson,
|
|
95
|
+
size: () => routesJson.length
|
|
96
|
+
};
|
|
97
|
+
callback();
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
shouldRegenerateRoutes() {
|
|
102
|
+
try {
|
|
103
|
+
const appFilePath = path.resolve(process.cwd(), this.options.appPath);
|
|
104
|
+
if (!fs.existsSync(appFilePath)) {
|
|
105
|
+
this.log('warn', `⚠️ App.tsx 文件不存在: ${appFilePath}`);
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
const currentHash = this.calculateFileHash(appFilePath);
|
|
109
|
+
if (this.lastAppPathHash === currentHash && this.cachedRoutes) {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
this.lastAppPathHash = currentHash;
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
this.log('warn', '⚠️ 检查文件变更时出错:', error.message);
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
calculateFileHash(filePath) {
|
|
121
|
+
try {
|
|
122
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
123
|
+
return crypto.createHash('md5').update(content).digest('hex');
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
this.log('warn', '⚠️ 计算文件哈希失败:', error.message);
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
parseRoutes() {
|
|
131
|
+
try {
|
|
132
|
+
const appFilePath = path.resolve(process.cwd(), this.options.appPath);
|
|
133
|
+
if (!fs.existsSync(appFilePath)) {
|
|
134
|
+
throw new Error(`App.tsx 文件不存在: ${appFilePath}`);
|
|
135
|
+
}
|
|
136
|
+
const sourceCode = fs.readFileSync(appFilePath, 'utf-8');
|
|
137
|
+
const ast = (0, parser_1.parse)(sourceCode, {
|
|
138
|
+
sourceType: 'module',
|
|
139
|
+
plugins: [
|
|
140
|
+
'jsx',
|
|
141
|
+
'typescript',
|
|
142
|
+
'decorators-legacy',
|
|
143
|
+
'classProperties',
|
|
144
|
+
'objectRestSpread',
|
|
145
|
+
'functionBind',
|
|
146
|
+
'exportDefaultFrom',
|
|
147
|
+
'exportNamespaceFrom',
|
|
148
|
+
'dynamicImport',
|
|
149
|
+
'nullishCoalescingOperator',
|
|
150
|
+
'optionalChaining'
|
|
151
|
+
]
|
|
152
|
+
});
|
|
153
|
+
const routeSet = new Set();
|
|
154
|
+
const routeStack = [];
|
|
155
|
+
const self = this;
|
|
156
|
+
(0, traverse_1.default)(ast, {
|
|
157
|
+
JSXElement: {
|
|
158
|
+
enter(path) {
|
|
159
|
+
const { openingElement } = path.node;
|
|
160
|
+
if (self.isRouteComponent(openingElement)) {
|
|
161
|
+
const routeInfo = self.extractRouteInfo(openingElement);
|
|
162
|
+
routeStack.push(routeInfo);
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
exit(path) {
|
|
166
|
+
const { openingElement } = path.node;
|
|
167
|
+
if (self.isRouteComponent(openingElement)) {
|
|
168
|
+
const currentRoute = routeStack.pop();
|
|
169
|
+
if (currentRoute && currentRoute.path === '*') {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
if (currentRoute && (currentRoute.path || currentRoute.index)) {
|
|
173
|
+
const fullPath = self.buildFullPath(routeStack, currentRoute);
|
|
174
|
+
if (fullPath) {
|
|
175
|
+
routeSet.add(fullPath);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
const routes = Array.from(routeSet).map(routePath => ({ path: routePath }));
|
|
183
|
+
return routes.length > 0 ? routes : [{ path: '/' }];
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
this.log('warn', '⚠️ 路由解析失败,使用默认路由:', error.message);
|
|
187
|
+
return [{ path: '/' }];
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
isRouteComponent(openingElement) {
|
|
191
|
+
return (t.isJSXIdentifier(openingElement.name) &&
|
|
192
|
+
openingElement.name.name === 'Route');
|
|
193
|
+
}
|
|
194
|
+
extractRouteInfo(openingElement) {
|
|
195
|
+
const routeInfo = {};
|
|
196
|
+
openingElement.attributes.forEach((attr) => {
|
|
197
|
+
if (t.isJSXAttribute(attr)) {
|
|
198
|
+
const name = attr.name.name;
|
|
199
|
+
let value;
|
|
200
|
+
if (attr.value) {
|
|
201
|
+
if (t.isStringLiteral(attr.value)) {
|
|
202
|
+
value = attr.value.value;
|
|
203
|
+
}
|
|
204
|
+
else if (t.isJSXExpressionContainer(attr.value)) {
|
|
205
|
+
const expression = attr.value.expression;
|
|
206
|
+
if (t.isStringLiteral(expression)) {
|
|
207
|
+
value = expression.value;
|
|
208
|
+
}
|
|
209
|
+
else if (t.isTemplateLiteral(expression)) {
|
|
210
|
+
value = this.evaluateTemplateLiteral(expression);
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
value = true;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
value = true;
|
|
219
|
+
}
|
|
220
|
+
routeInfo[name] = value;
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
return routeInfo;
|
|
224
|
+
}
|
|
225
|
+
buildFullPath(routeStack, currentRoute) {
|
|
226
|
+
let fullPath = '';
|
|
227
|
+
for (let i = 0; i < routeStack.length; i++) {
|
|
228
|
+
if (routeStack[i].path) {
|
|
229
|
+
let parentPath = routeStack[i].path;
|
|
230
|
+
if (!parentPath.startsWith('/'))
|
|
231
|
+
parentPath = `/${parentPath}`;
|
|
232
|
+
if (parentPath.endsWith('/') && parentPath !== '/') {
|
|
233
|
+
parentPath = parentPath.slice(0, -1);
|
|
234
|
+
}
|
|
235
|
+
fullPath += parentPath === '/' ? '' : parentPath;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
if (currentRoute.index) {
|
|
239
|
+
return fullPath || '/';
|
|
240
|
+
}
|
|
241
|
+
else if (currentRoute.path) {
|
|
242
|
+
const routePath = currentRoute.path;
|
|
243
|
+
if (routePath === '*') {
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
if (!routePath.startsWith('/')) {
|
|
247
|
+
fullPath = `${fullPath}/${routePath}`;
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
fullPath = routePath;
|
|
251
|
+
}
|
|
252
|
+
if (fullPath === '')
|
|
253
|
+
fullPath = '/';
|
|
254
|
+
if (!fullPath.startsWith('/'))
|
|
255
|
+
fullPath = `/${fullPath}`;
|
|
256
|
+
return fullPath;
|
|
257
|
+
}
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
evaluateTemplateLiteral(templateLiteral) {
|
|
261
|
+
const quasis = templateLiteral.quasis;
|
|
262
|
+
const expressions = templateLiteral.expressions;
|
|
263
|
+
if (quasis.length === 1 && expressions.length === 0) {
|
|
264
|
+
return quasis[0].value.raw;
|
|
265
|
+
}
|
|
266
|
+
return quasis.map((q) => q.value.raw).join('');
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
exports.default = RouteParserPlugin;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface SlardarPerformanceMonitorPluginOptions {
|
|
2
|
+
position?: 'head-end' | 'body-start' | 'body-end';
|
|
3
|
+
snippet?: string;
|
|
4
|
+
}
|
|
5
|
+
declare class SlardarPerformanceMonitorPlugin {
|
|
6
|
+
private options;
|
|
7
|
+
constructor(options?: SlardarPerformanceMonitorPluginOptions);
|
|
8
|
+
apply(compiler: any): void;
|
|
9
|
+
}
|
|
10
|
+
export default SlardarPerformanceMonitorPlugin;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
class SlardarPerformanceMonitorPlugin {
|
|
4
|
+
constructor(options) {
|
|
5
|
+
this.options = options || {};
|
|
6
|
+
}
|
|
7
|
+
apply(compiler) {
|
|
8
|
+
compiler.hooks.compilation.tap('SlardarPerformanceMonitorPlugin', (compilation) => {
|
|
9
|
+
try {
|
|
10
|
+
let HtmlPlugin;
|
|
11
|
+
try {
|
|
12
|
+
HtmlPlugin = require('@rspack/core').rspack.HtmlRspackPlugin;
|
|
13
|
+
}
|
|
14
|
+
catch (e) {
|
|
15
|
+
try {
|
|
16
|
+
HtmlPlugin = require('html-webpack-plugin');
|
|
17
|
+
}
|
|
18
|
+
catch (e2) {
|
|
19
|
+
console.warn('SlardarPerformanceMonitorPlugin: html-rspack-plugin or html-webpack-plugin not found');
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const hooks = HtmlPlugin.getHooks(compilation);
|
|
24
|
+
hooks.beforeEmit.tapAsync('SlardarPerformanceMonitorPlugin', (data, cb) => {
|
|
25
|
+
const position = this.options.position ?? 'head-end';
|
|
26
|
+
const snippet = this.options.snippet ?? getSlardarScript();
|
|
27
|
+
if (!snippet)
|
|
28
|
+
return;
|
|
29
|
+
if (position === 'body-end') {
|
|
30
|
+
data.html = data.html.replace('</body>', `${snippet}\n</body>`);
|
|
31
|
+
}
|
|
32
|
+
else if (position === 'body-start') {
|
|
33
|
+
data.html = data.html.replace('<body>', `<body>\n${snippet}`);
|
|
34
|
+
}
|
|
35
|
+
else if (position === 'head-end') {
|
|
36
|
+
data.html = data.html.replace('</head>', `${snippet}\n</head>`);
|
|
37
|
+
}
|
|
38
|
+
cb(null, data);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
console.error('Error in SlardarPerformanceMonitorPlugin:', error);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
exports.default = SlardarPerformanceMonitorPlugin;
|
|
48
|
+
function getSlardarScript(option = {}) {
|
|
49
|
+
const bid = option.bid || 'apaas_ai';
|
|
50
|
+
const globalName = option.globalName || 'KSlardarWeb';
|
|
51
|
+
return `
|
|
52
|
+
<script>
|
|
53
|
+
// 创建 Slardar 脚本元素
|
|
54
|
+
const slardarScript = document.createElement('script');
|
|
55
|
+
slardarScript.src = 'https://lf3-short.ibytedapm.com/slardar/fe/sdk-web/browser.cn.js?bid=${bid}&globalName=${globalName}';
|
|
56
|
+
slardarScript.crossOrigin = 'anonymous';
|
|
57
|
+
|
|
58
|
+
// 添加 onload 事件处理
|
|
59
|
+
slardarScript.onload = function() {
|
|
60
|
+
// 脚本加载完成后执行初始化
|
|
61
|
+
if (window.KSlardarWeb) {
|
|
62
|
+
window.KSlardarWeb('init', {
|
|
63
|
+
bid: 'apaas_ai',
|
|
64
|
+
// 四种类型:dev/boe/pre/online
|
|
65
|
+
env: 'online',
|
|
66
|
+
});
|
|
67
|
+
window.KSlardarWeb('start');
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// 添加错误处理
|
|
72
|
+
slardarScript.onerror = function() {
|
|
73
|
+
console.warn('Failed to load Slardar script');
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// 将脚本添加到页面
|
|
77
|
+
document.head.appendChild(slardarScript);
|
|
78
|
+
|
|
79
|
+
// 添加 TTI 监控脚本
|
|
80
|
+
const performanceScript = document.createElement('script');
|
|
81
|
+
performanceScript.src = 'https://sf3-scmcdn-cn.feishucdn.com/obj/unpkg/byted/performance/0.1.0/dist/performance.iife.js';
|
|
82
|
+
document.head.appendChild(performanceScript);
|
|
83
|
+
</script>
|
|
84
|
+
|
|
85
|
+
`;
|
|
86
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.listenHmrTiming = listenHmrTiming;
|
|
37
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
/**
|
|
40
|
+
* 监听 HMR 编译时间
|
|
41
|
+
* @param server
|
|
42
|
+
*/
|
|
43
|
+
function listenHmrTiming(server) {
|
|
44
|
+
const compiler = server.compiler;
|
|
45
|
+
const ws = server.webSocketServer;
|
|
46
|
+
let start = 0;
|
|
47
|
+
let changedFiles = new Set();
|
|
48
|
+
// 监听文件变更
|
|
49
|
+
compiler.hooks.watchRun.tap('HmrTiming', (comp) => {
|
|
50
|
+
const modifiedFiles = comp.modifiedFiles;
|
|
51
|
+
if (modifiedFiles && modifiedFiles.size > 0) {
|
|
52
|
+
changedFiles = new Set(modifiedFiles);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
changedFiles.clear();
|
|
56
|
+
}
|
|
57
|
+
start = Date.now();
|
|
58
|
+
});
|
|
59
|
+
// 编译完成
|
|
60
|
+
compiler.hooks.done.tap('HmrTiming', () => {
|
|
61
|
+
const duration = Date.now() - start;
|
|
62
|
+
// 过滤有效文件 - 只保留实际的项目文件
|
|
63
|
+
const validFiles = [...changedFiles]
|
|
64
|
+
.map(f => f.replace(process.cwd(), '').replace(/\\/g, '/'))
|
|
65
|
+
.filter(filePath => {
|
|
66
|
+
// 过滤无效文件
|
|
67
|
+
if (!filePath || filePath.length === 0)
|
|
68
|
+
return false;
|
|
69
|
+
// 过滤 node_modules 中的文件
|
|
70
|
+
if (filePath.includes('/node_modules/'))
|
|
71
|
+
return false;
|
|
72
|
+
// 只保留支持的文件类型
|
|
73
|
+
const validExtensions = ['.js', '.jsx', '.ts', '.tsx', '.svelte', '.css', '.json', '.html'];
|
|
74
|
+
const hasValidExtension = validExtensions.some(ext => filePath.toLowerCase().endsWith(ext));
|
|
75
|
+
if (!hasValidExtension)
|
|
76
|
+
return false;
|
|
77
|
+
return true;
|
|
78
|
+
});
|
|
79
|
+
// 获取文件统计信息
|
|
80
|
+
const fileStats = validFiles.map(filePath => {
|
|
81
|
+
const fullPath = process.cwd() + filePath;
|
|
82
|
+
try {
|
|
83
|
+
const stats = fs.statSync(fullPath);
|
|
84
|
+
return {
|
|
85
|
+
path: filePath,
|
|
86
|
+
size: stats.size,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
return {
|
|
91
|
+
path: filePath,
|
|
92
|
+
size: 0,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
// 计算总文件大小(B)
|
|
97
|
+
const totalSize = fileStats.reduce((sum, file) => sum + file.size, 0);
|
|
98
|
+
const payload = {
|
|
99
|
+
duration,
|
|
100
|
+
fileCount: validFiles.length,
|
|
101
|
+
fileTotalSize: totalSize,
|
|
102
|
+
};
|
|
103
|
+
// 推送到浏览器端
|
|
104
|
+
for (const client of ws.clients) {
|
|
105
|
+
if (client.readyState === 1) {
|
|
106
|
+
client.send(JSON.stringify({
|
|
107
|
+
type: 'hmr-timing',
|
|
108
|
+
data: payload,
|
|
109
|
+
}));
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lark-apaas/fullstack-rspack-preset",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"files": [
|
|
5
|
+
"lib"
|
|
6
|
+
],
|
|
7
|
+
"main": "./lib/index.js",
|
|
8
|
+
"types": "./lib/index.d.ts",
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"keywords": [
|
|
11
|
+
"fullstack",
|
|
12
|
+
"rspack",
|
|
13
|
+
"presets"
|
|
14
|
+
],
|
|
15
|
+
"publishConfig": {
|
|
16
|
+
"access": "public"
|
|
17
|
+
},
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc",
|
|
20
|
+
"watch": "tsc --watch",
|
|
21
|
+
"test": "vitest run",
|
|
22
|
+
"test:watch": "vitest",
|
|
23
|
+
"prepublishOnly": "npm run build"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@lark-apaas/miaoda-inspector-babel-plugin": "^1.0.0",
|
|
27
|
+
"@lark-apaas/miaoda-inspector-jsx-runtime": "^1.0.0",
|
|
28
|
+
"clsx": "^2.1.1",
|
|
29
|
+
"echarts": "^6.0.0",
|
|
30
|
+
"postcss-import": "^16.1.1",
|
|
31
|
+
"tailwind-merge": "^2.5.5"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@lark-apaas/devtool-kits": "^1.0.0",
|
|
35
|
+
"@rspack/core": "^1.4.4",
|
|
36
|
+
"@types/node": "^22.15.30",
|
|
37
|
+
"typescript": "^5.9.2",
|
|
38
|
+
"vitest": "^2.1.8"
|
|
39
|
+
},
|
|
40
|
+
"peerDependencies": {
|
|
41
|
+
"@lark-apaas/devtool-kits": "^1.0.0",
|
|
42
|
+
"@rspack/core": ">=1.0.0"
|
|
43
|
+
}
|
|
44
|
+
}
|