@lark-apaas/miaoda-presets 1.0.2 → 1.0.4
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/lib/overlay/index.js
CHANGED
|
@@ -167,6 +167,14 @@ function render() {
|
|
|
167
167
|
const origin = targetOrigin || getPreviewParentOrigin();
|
|
168
168
|
window.parent.postMessage(message, origin);
|
|
169
169
|
};
|
|
170
|
+
// 通知主应用存在自定义 overlay
|
|
171
|
+
sendPostMessage({
|
|
172
|
+
type: 'app-features',
|
|
173
|
+
payload: [{
|
|
174
|
+
feature: 'error-overlay',
|
|
175
|
+
enable: true,
|
|
176
|
+
}],
|
|
177
|
+
});
|
|
170
178
|
if (currentCompileErrorMessage) {
|
|
171
179
|
currentMode = 'compileError';
|
|
172
180
|
ErrorContainer(rootDocument, root, {
|
package/lib/recommend/rspack.js
CHANGED
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.createRecommendRspackConfig = createRecommendRspackConfig;
|
|
7
7
|
const path_1 = __importDefault(require("path"));
|
|
8
8
|
const core_1 = __importDefault(require("@rspack/core"));
|
|
9
|
+
const dev_server_listener_1 = require("../utils/dev-server-listener");
|
|
9
10
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
10
11
|
const RouteParserPlugin = require('../rspack-plugins/route-parser-plugin');
|
|
11
12
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
@@ -123,7 +124,9 @@ function createRecommendRspackConfig(options) {
|
|
|
123
124
|
maxChunks: 1,
|
|
124
125
|
}),
|
|
125
126
|
// 全栈模式下,增加性能监控上报脚本注入
|
|
126
|
-
runtimeMode === 'fullstack'
|
|
127
|
+
runtimeMode === 'fullstack'
|
|
128
|
+
? new SlardarPerformanceMonitorPlugin()
|
|
129
|
+
: undefined,
|
|
127
130
|
// 开发环境下,解析路由
|
|
128
131
|
isDev &&
|
|
129
132
|
needRoutes &&
|
|
@@ -177,7 +180,7 @@ function createRecommendRspackConfig(options) {
|
|
|
177
180
|
},
|
|
178
181
|
devtool: isDev ? 'source-map' : false, // 对应vite的sourcemap配置
|
|
179
182
|
devServer: {
|
|
180
|
-
headers:
|
|
183
|
+
headers: req => {
|
|
181
184
|
// 获取请求的Origin头
|
|
182
185
|
const requestOrigin = req.headers.origin ?? '';
|
|
183
186
|
// 定义允许的域名白名单
|
|
@@ -194,12 +197,17 @@ function createRecommendRspackConfig(options) {
|
|
|
194
197
|
'Access-Control-Allow-Origin': allowedOrigin,
|
|
195
198
|
};
|
|
196
199
|
},
|
|
200
|
+
onListening(server) {
|
|
201
|
+
if (runtimeMode === 'fullstack') {
|
|
202
|
+
(0, dev_server_listener_1.listenHmrTiming)(server);
|
|
203
|
+
}
|
|
204
|
+
},
|
|
197
205
|
client: {
|
|
198
206
|
overlay: {
|
|
199
207
|
errors: false,
|
|
200
208
|
warnings: false,
|
|
201
|
-
}
|
|
202
|
-
}
|
|
209
|
+
},
|
|
210
|
+
},
|
|
203
211
|
},
|
|
204
212
|
};
|
|
205
213
|
}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Webpack HMR 耗时计算插件 JavaScript 版本
|
|
4
|
+
* 在浏览器 Console 打印热更文件和耗时信息
|
|
5
|
+
*/
|
|
6
|
+
class HMRTimingPlugin {
|
|
7
|
+
constructor(options = {}) {
|
|
8
|
+
this.options = {
|
|
9
|
+
threshold: options.threshold || 1000
|
|
10
|
+
};
|
|
11
|
+
this.hmrStartTime = null;
|
|
12
|
+
this.changedFiles = new Set();
|
|
13
|
+
this.devServer = null;
|
|
14
|
+
}
|
|
15
|
+
apply(compiler) {
|
|
16
|
+
const pluginName = 'HMRTimingPlugin';
|
|
17
|
+
// 在 devServer 启动后保存引用
|
|
18
|
+
if (compiler.options.devServer) {
|
|
19
|
+
const originalSetupMiddlewares = compiler.options.devServer.setupMiddlewares;
|
|
20
|
+
const self = this;
|
|
21
|
+
compiler.options.devServer.setupMiddlewares = function (middlewares, devServer) {
|
|
22
|
+
// 保存 devServer 实例的引用
|
|
23
|
+
self.devServer = devServer;
|
|
24
|
+
global.__webpack_dev_server__ = devServer;
|
|
25
|
+
if (originalSetupMiddlewares) {
|
|
26
|
+
return originalSetupMiddlewares(middlewares, devServer);
|
|
27
|
+
}
|
|
28
|
+
return middlewares;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
// 监听文件变化
|
|
32
|
+
compiler.hooks.invalid.tap(pluginName, (fileName) => {
|
|
33
|
+
this.hmrStartTime = Date.now();
|
|
34
|
+
this.changedFiles.clear();
|
|
35
|
+
if (fileName) {
|
|
36
|
+
this.changedFiles.add(fileName);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
// 监听 watch 运行开始
|
|
40
|
+
compiler.hooks.watchRun.tapAsync(pluginName, (compiler, callback) => {
|
|
41
|
+
if (!this.hmrStartTime) {
|
|
42
|
+
this.hmrStartTime = Date.now();
|
|
43
|
+
}
|
|
44
|
+
// 收集变化的文件
|
|
45
|
+
if (compiler.modifiedFiles) {
|
|
46
|
+
compiler.modifiedFiles.forEach(file => this.changedFiles.add(file));
|
|
47
|
+
}
|
|
48
|
+
if (compiler.removedFiles) {
|
|
49
|
+
compiler.removedFiles.forEach(file => this.changedFiles.add(file));
|
|
50
|
+
}
|
|
51
|
+
callback();
|
|
52
|
+
});
|
|
53
|
+
// 监听编译完成
|
|
54
|
+
compiler.hooks.done.tap(pluginName, (stats) => {
|
|
55
|
+
if (this.hmrStartTime === null)
|
|
56
|
+
return;
|
|
57
|
+
const totalTime = Date.now() - this.hmrStartTime;
|
|
58
|
+
// 获取实际更新的模块
|
|
59
|
+
const updatedModules = new Set();
|
|
60
|
+
stats.compilation.modules.forEach(module => {
|
|
61
|
+
const identifier = module.resource || module.identifier?.();
|
|
62
|
+
if (identifier && typeof identifier === 'string') {
|
|
63
|
+
// 过滤掉 node_modules 中的模块
|
|
64
|
+
if (!identifier.includes('node_modules')) {
|
|
65
|
+
updatedModules.add(identifier);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
// 合并文件列表
|
|
70
|
+
const allChangedFiles = new Set([
|
|
71
|
+
...Array.from(this.changedFiles),
|
|
72
|
+
...Array.from(updatedModules)
|
|
73
|
+
]);
|
|
74
|
+
// 简化文件路径
|
|
75
|
+
const simplifiedFiles = Array.from(allChangedFiles)
|
|
76
|
+
.map(file => {
|
|
77
|
+
// 移除项目根路径
|
|
78
|
+
const relativePath = file.replace(compiler.context || '', '');
|
|
79
|
+
// 移除开头的斜杠
|
|
80
|
+
return relativePath.replace(/^[\/\\]/, '');
|
|
81
|
+
})
|
|
82
|
+
.filter(file => file && file.length > 0)
|
|
83
|
+
.slice(0, 10); // 最多显示10个文件
|
|
84
|
+
const timingInfo = {
|
|
85
|
+
totalTime,
|
|
86
|
+
changedFiles: simplifiedFiles,
|
|
87
|
+
modules: stats.compilation.modules.size,
|
|
88
|
+
isOverThreshold: totalTime > this.options.threshold,
|
|
89
|
+
threshold: this.options.threshold
|
|
90
|
+
};
|
|
91
|
+
// 通过 WebSocket 发送到浏览器
|
|
92
|
+
this.sendToBrowser(compiler, timingInfo);
|
|
93
|
+
// 重置
|
|
94
|
+
this.changedFiles.clear();
|
|
95
|
+
});
|
|
96
|
+
// 注入客户端代码
|
|
97
|
+
this.injectClientScript(compiler);
|
|
98
|
+
}
|
|
99
|
+
sendToBrowser(compiler, timingInfo) {
|
|
100
|
+
// 使用 done hook 确保在编译完成后发送
|
|
101
|
+
const server = this.getDevServer(compiler);
|
|
102
|
+
if (server) {
|
|
103
|
+
if (server.sockWrite) {
|
|
104
|
+
// webpack-dev-server 3.x
|
|
105
|
+
server.sockWrite(server.sockets, 'hmr-timing', timingInfo);
|
|
106
|
+
}
|
|
107
|
+
else if (server.sendMessage) {
|
|
108
|
+
// webpack-dev-server 4.x/5.x
|
|
109
|
+
const clients = server.webSocketServer?.clients || server.clients;
|
|
110
|
+
server.sendMessage(clients, 'hmr-timing', timingInfo);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
getDevServer(compiler) {
|
|
115
|
+
// 尝试多种方式获取 devServer 实例
|
|
116
|
+
// 方式1: 从 compiler.options.devServer 存储的引用
|
|
117
|
+
if (compiler.options.devServer && compiler.options.devServer.__instance) {
|
|
118
|
+
return compiler.options.devServer.__instance;
|
|
119
|
+
}
|
|
120
|
+
// 方式2: 从全局变量
|
|
121
|
+
if (global.__webpack_dev_server__) {
|
|
122
|
+
return global.__webpack_dev_server__;
|
|
123
|
+
}
|
|
124
|
+
// 方式3: 从 compiler 上挂载的引用
|
|
125
|
+
if (compiler.__webpack_dev_server__) {
|
|
126
|
+
return compiler.__webpack_dev_server__;
|
|
127
|
+
}
|
|
128
|
+
// 方式4: 在 infrastructure 日志中查找
|
|
129
|
+
if (compiler.infrastructureLogger) {
|
|
130
|
+
const logger = compiler.infrastructureLogger;
|
|
131
|
+
if (logger.__devServer) {
|
|
132
|
+
return logger.__devServer;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
injectClientScript(compiler) {
|
|
138
|
+
const clientScript = `
|
|
139
|
+
;(function() {
|
|
140
|
+
if (typeof window === 'undefined' || !module.hot) return;
|
|
141
|
+
|
|
142
|
+
const threshold = ${this.options.threshold};
|
|
143
|
+
|
|
144
|
+
// 显示 HMR 耗时和变化文件
|
|
145
|
+
function logHMRTiming(data) {
|
|
146
|
+
const color = data.isOverThreshold ? '#ff9800' : '#4caf50';
|
|
147
|
+
|
|
148
|
+
// 主要信息
|
|
149
|
+
console.log(
|
|
150
|
+
'%c🔥 HMR 更新完成 - 耗时: %c' + data.totalTime + 'ms',
|
|
151
|
+
'color: ' + color + '; font-weight: bold; font-size: 14px;',
|
|
152
|
+
'color: ' + color + '; font-weight: bold; font-size: 16px;'
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
// 热更文件列表
|
|
156
|
+
if (data.changedFiles && data.changedFiles.length > 0) {
|
|
157
|
+
console.group('📝 热更文件 (' + data.changedFiles.length + ')');
|
|
158
|
+
data.changedFiles.forEach(function(file) {
|
|
159
|
+
console.log(' •', file);
|
|
160
|
+
});
|
|
161
|
+
console.groupEnd();
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// 超过阈值警告
|
|
165
|
+
if (data.isOverThreshold) {
|
|
166
|
+
console.warn('⚠️ HMR 耗时超过阈值 ' + threshold + 'ms');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
console.log(''); // 空行分隔
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// 监听 webpack-dev-server 的 WebSocket 消息
|
|
173
|
+
if (typeof __webpack_dev_server_client__ !== 'undefined') {
|
|
174
|
+
// webpack-dev-server 4.x/5.x
|
|
175
|
+
const originalOnMessage = __webpack_dev_server_client__.onMessage;
|
|
176
|
+
__webpack_dev_server_client__.onMessage = function(message) {
|
|
177
|
+
if (message.type === 'hmr-timing') {
|
|
178
|
+
logHMRTiming(message.data);
|
|
179
|
+
}
|
|
180
|
+
if (originalOnMessage) {
|
|
181
|
+
return originalOnMessage.apply(this, arguments);
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
} else {
|
|
185
|
+
// 备用方案:监听 WebSocket
|
|
186
|
+
setTimeout(function() {
|
|
187
|
+
const ws = window.__webpack_dev_server_ws__;
|
|
188
|
+
if (ws && ws.addEventListener) {
|
|
189
|
+
ws.addEventListener('message', function(event) {
|
|
190
|
+
try {
|
|
191
|
+
const message = JSON.parse(event.data);
|
|
192
|
+
if (message.type === 'hmr-timing') {
|
|
193
|
+
logHMRTiming(message.data);
|
|
194
|
+
}
|
|
195
|
+
} catch (e) {}
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
}, 1000);
|
|
199
|
+
}
|
|
200
|
+
})();
|
|
201
|
+
`;
|
|
202
|
+
compiler.hooks.compilation.tap('HMRTimingPlugin', (compilation) => {
|
|
203
|
+
compilation.hooks.processAssets.tap({
|
|
204
|
+
name: 'HMRTimingPlugin',
|
|
205
|
+
stage: compilation.constructor.PROCESS_ASSETS_STAGE_ADDITIONAL,
|
|
206
|
+
}, () => {
|
|
207
|
+
// 注入到主入口文件
|
|
208
|
+
const mainAssets = Object.keys(compilation.assets).filter(name => name.match(/^(main|index|app|bundle).*\.js$/) && !name.includes('hot-update'));
|
|
209
|
+
if (mainAssets.length > 0) {
|
|
210
|
+
const assetName = mainAssets[0];
|
|
211
|
+
const asset = compilation.assets[assetName];
|
|
212
|
+
const source = asset.source();
|
|
213
|
+
const newSource = clientScript + '\n' + source;
|
|
214
|
+
compilation.assets[assetName] = {
|
|
215
|
+
source: () => newSource,
|
|
216
|
+
size: () => newSource.length,
|
|
217
|
+
map: () => asset.map ? asset.map() : null
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
module.exports = HMRTimingPlugin;
|
|
225
|
+
/**
|
|
226
|
+
* 使用示例:
|
|
227
|
+
*
|
|
228
|
+
* // webpack.config.js
|
|
229
|
+
* const HMRTimingPlugin = require('./HMRTimingPlugin');
|
|
230
|
+
*
|
|
231
|
+
* module.exports = {
|
|
232
|
+
* mode: 'development',
|
|
233
|
+
* devServer: {
|
|
234
|
+
* hot: true,
|
|
235
|
+
* },
|
|
236
|
+
* plugins: [
|
|
237
|
+
* new HMRTimingPlugin({
|
|
238
|
+
* threshold: 1000 // 超过1秒会显示警告
|
|
239
|
+
* })
|
|
240
|
+
* ]
|
|
241
|
+
* };
|
|
242
|
+
*
|
|
243
|
+
* 浏览器控制台输出示例:
|
|
244
|
+
*
|
|
245
|
+
* 🔥 HMR 更新完成 - 耗时: 523ms
|
|
246
|
+
* 📝 热更文件 (2)
|
|
247
|
+
* • src/components/App.jsx
|
|
248
|
+
* • src/styles/main.css
|
|
249
|
+
*
|
|
250
|
+
* 🔥 HMR 更新完成 - 耗时: 1250ms
|
|
251
|
+
* 📝 热更文件 (1)
|
|
252
|
+
* • src/utils/helper.js
|
|
253
|
+
* ⚠️ HMR 耗时超过阈值 1000ms
|
|
254
|
+
*
|
|
255
|
+
* 功能特性:
|
|
256
|
+
* - 显示 HMR 耗时(带颜色提示)
|
|
257
|
+
* - 显示热更新的文件列表(可折叠)
|
|
258
|
+
* - 超过阈值时显示警告
|
|
259
|
+
* - 通过 DevServer WebSocket 通信
|
|
260
|
+
* - 自动过滤 node_modules
|
|
261
|
+
* - 简化文件路径显示
|
|
262
|
+
*/
|
|
@@ -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
|
+
}
|