@lytjs/hmr 6.5.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/README.md ADDED
@@ -0,0 +1,79 @@
1
+ # @lytjs/hmr
2
+
3
+ LytJS 热模块替换(Hot Module Replacement)支持。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ pnpm add -D @lytjs/hmr
9
+ ```
10
+
11
+ ## 快速开始
12
+
13
+ ```typescript
14
+ import { createHMRClient, getHMRClient, accept } from '@lytjs/hmr';
15
+
16
+ // 创建 HMR 客户端
17
+ const client = createHMRClient({
18
+ url: 'ws://localhost:5173',
19
+ autoConnect: true,
20
+ });
21
+
22
+ // 或者使用全局单例
23
+ const globalClient = getHMRClient();
24
+
25
+ // 接受模块更新
26
+ accept('/path/to/module.ts', (update) => {
27
+ console.log('模块已更新:', update);
28
+ });
29
+ ```
30
+
31
+ ## 特性
32
+
33
+ - WebSocket 连接管理
34
+ - 模块更新处理
35
+ - 自动重连
36
+ - 状态保持
37
+
38
+ ## API
39
+
40
+ ### createHMRClient(options)
41
+
42
+ 创建 HMR 客户端实例。
43
+
44
+ ```typescript
45
+ import { createHMRClient } from '@lytjs/hmr';
46
+
47
+ const client = createHMRClient({
48
+ url: 'ws://localhost:5173',
49
+ autoConnect: true,
50
+ });
51
+ ```
52
+
53
+ ### getHMRClient(options)
54
+
55
+ 获取全局 HMR 客户端单例。
56
+
57
+ ### accept(path, handler)
58
+
59
+ 注册模块更新处理函数。
60
+
61
+ ### dispose(path, handler)
62
+
63
+ 注册模块清理函数。
64
+
65
+ ### client.connect()
66
+
67
+ 连接到 HMR 服务器。
68
+
69
+ ### client.disconnect()
70
+
71
+ 断开连接。
72
+
73
+ ### client.send(message)
74
+
75
+ 发送消息。
76
+
77
+ ## 许可证
78
+
79
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,179 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ accept: () => accept,
24
+ createHMRClient: () => createHMRClient,
25
+ dispose: () => dispose,
26
+ getHMRClient: () => getHMRClient
27
+ });
28
+ module.exports = __toCommonJS(index_exports);
29
+ var HMRClient = class {
30
+ constructor(options = {}) {
31
+ this.ws = null;
32
+ this.handlers = /* @__PURE__ */ new Map();
33
+ this.isConnected = false;
34
+ this.options = {
35
+ url: options.url || "ws://localhost:5173",
36
+ autoConnect: options.autoConnect !== false
37
+ };
38
+ if (this.options.autoConnect) {
39
+ this.connect();
40
+ }
41
+ }
42
+ /**
43
+ * 连接到 HMR 服务器
44
+ */
45
+ connect() {
46
+ if (this.ws) {
47
+ this.ws.close();
48
+ }
49
+ console.log("[HMR] Connecting to", this.options.url);
50
+ try {
51
+ this.ws = new WebSocket(this.options.url);
52
+ this.ws.onopen = () => {
53
+ this.isConnected = true;
54
+ console.log("[HMR] Connected");
55
+ this.dispatch({ type: "connected" });
56
+ };
57
+ this.ws.onmessage = (event) => {
58
+ this.handleMessage(event.data);
59
+ };
60
+ this.ws.onclose = () => {
61
+ this.isConnected = false;
62
+ console.log("[HMR] Disconnected, reconnecting in 2s...");
63
+ setTimeout(() => this.connect(), 2e3);
64
+ };
65
+ this.ws.onerror = (error) => {
66
+ console.error("[HMR] WebSocket error", error);
67
+ };
68
+ } catch (error) {
69
+ console.error("[HMR] Connection failed", error);
70
+ setTimeout(() => this.connect(), 2e3);
71
+ }
72
+ }
73
+ /**
74
+ * 处理消息
75
+ */
76
+ handleMessage(data) {
77
+ try {
78
+ const message = JSON.parse(data);
79
+ console.log("[HMR] Received message:", message.type);
80
+ switch (message.type) {
81
+ case "update":
82
+ this.handleUpdate(message.data);
83
+ break;
84
+ case "full-reload":
85
+ this.handleFullReload();
86
+ break;
87
+ default:
88
+ this.dispatch(message);
89
+ break;
90
+ }
91
+ } catch (error) {
92
+ console.error("[HMR] Failed to parse message", error);
93
+ }
94
+ }
95
+ /**
96
+ * 处理模块更新
97
+ */
98
+ handleUpdate(update) {
99
+ const handler = this.handlers.get(update.path);
100
+ if (handler?.accept) {
101
+ console.log("[HMR] Accepting update for", update.path);
102
+ handler.accept(update);
103
+ } else {
104
+ console.log("[HMR] No handler for", update.path, ", reloading");
105
+ this.handleFullReload();
106
+ }
107
+ }
108
+ /**
109
+ * 处理完全重新加载
110
+ */
111
+ handleFullReload() {
112
+ console.log("[HMR] Full reload requested");
113
+ window.location.reload();
114
+ }
115
+ /**
116
+ * 注册模块处理程序
117
+ */
118
+ register(path, handler) {
119
+ this.handlers.set(path, handler);
120
+ }
121
+ /**
122
+ * 注销模块处理程序
123
+ */
124
+ unregister(path) {
125
+ this.handlers.delete(path);
126
+ }
127
+ /**
128
+ * 发送消息到服务器
129
+ */
130
+ send(message) {
131
+ if (this.ws && this.isConnected) {
132
+ this.ws.send(JSON.stringify(message));
133
+ }
134
+ }
135
+ /**
136
+ * 分发事件
137
+ */
138
+ dispatch(message) {
139
+ const event = new CustomEvent("lytjs:hmr", {
140
+ detail: message
141
+ });
142
+ window.dispatchEvent(event);
143
+ }
144
+ /**
145
+ * 断开连接
146
+ */
147
+ disconnect() {
148
+ if (this.ws) {
149
+ this.ws.close();
150
+ this.ws = null;
151
+ }
152
+ }
153
+ };
154
+ function createHMRClient(options = {}) {
155
+ return new HMRClient(options);
156
+ }
157
+ var globalClient = null;
158
+ function getHMRClient(options = {}) {
159
+ if (!globalClient) {
160
+ globalClient = createHMRClient(options);
161
+ }
162
+ return globalClient;
163
+ }
164
+ function accept(path, handler) {
165
+ const client = getHMRClient();
166
+ client.register(path, { accept: handler });
167
+ }
168
+ function dispose(path, handler) {
169
+ const client = getHMRClient();
170
+ const existing = client["handlers"].get(path) || {};
171
+ client.register(path, { ...existing, dispose: handler });
172
+ }
173
+ // Annotate the CommonJS export names for ESM import in node:
174
+ 0 && (module.exports = {
175
+ accept,
176
+ createHMRClient,
177
+ dispose,
178
+ getHMRClient
179
+ });
@@ -0,0 +1,114 @@
1
+ /**
2
+ * @lytjs/hmr - Type definitions
3
+ */
4
+ interface HMRClientOptions {
5
+ /** WebSocket URL */
6
+ url?: string;
7
+ /** 是否自动连接 */
8
+ autoConnect?: boolean;
9
+ }
10
+ interface HMRMessage {
11
+ /** 消息类型 */
12
+ type: 'connected' | 'update' | 'full-reload' | 'custom';
13
+ /** 数据 */
14
+ data?: any;
15
+ }
16
+ interface HMRUpdate {
17
+ /** 模块路径 */
18
+ path: string;
19
+ /** 更新时间戳 */
20
+ timestamp: number;
21
+ /** 是否需要保留状态 */
22
+ preserveState?: boolean;
23
+ }
24
+ interface HMRHandler {
25
+ /** 接受更新 */
26
+ accept?: (update: HMRUpdate) => void;
27
+ /** 处理错误 */
28
+ error?: (error: Error) => void;
29
+ /** 清理旧模块 */
30
+ dispose?: () => void;
31
+ }
32
+
33
+ /**
34
+ * @lytjs/hmr - LytJS 热模块替换
35
+ *
36
+ * 提供热模块替换的核心功能
37
+ */
38
+
39
+ /**
40
+ * HMR 客户端类
41
+ */
42
+ declare class HMRClient {
43
+ private options;
44
+ private ws;
45
+ private handlers;
46
+ private isConnected;
47
+ constructor(options?: HMRClientOptions);
48
+ /**
49
+ * 连接到 HMR 服务器
50
+ */
51
+ connect(): void;
52
+ /**
53
+ * 处理消息
54
+ */
55
+ private handleMessage;
56
+ /**
57
+ * 处理模块更新
58
+ */
59
+ private handleUpdate;
60
+ /**
61
+ * 处理完全重新加载
62
+ */
63
+ private handleFullReload;
64
+ /**
65
+ * 注册模块处理程序
66
+ */
67
+ register(path: string, handler: HMRHandler): void;
68
+ /**
69
+ * 注销模块处理程序
70
+ */
71
+ unregister(path: string): void;
72
+ /**
73
+ * 发送消息到服务器
74
+ */
75
+ send(message: HMRMessage): void;
76
+ /**
77
+ * 分发事件
78
+ */
79
+ private dispatch;
80
+ /**
81
+ * 断开连接
82
+ */
83
+ disconnect(): void;
84
+ }
85
+ /**
86
+ * 创建 HMR 客户端
87
+ *
88
+ * @param options - 客户端选项
89
+ * @returns HMR 客户端实例
90
+ */
91
+ declare function createHMRClient(options?: HMRClientOptions): HMRClient;
92
+ /**
93
+ * 获取全局 HMR 客户端
94
+ *
95
+ * @param options - 客户端选项(首次调用时使用)
96
+ * @returns HMR 客户端实例
97
+ */
98
+ declare function getHMRClient(options?: HMRClientOptions): HMRClient;
99
+ /**
100
+ * HMR 模块接受函数
101
+ *
102
+ * @param path - 模块路径
103
+ * @param handler - 处理程序
104
+ */
105
+ declare function accept(path: string, handler: (update: HMRUpdate) => void): void;
106
+ /**
107
+ * HMR 模块清理函数
108
+ *
109
+ * @param path - 模块路径
110
+ * @param handler - 清理函数
111
+ */
112
+ declare function dispose(path: string, handler: () => void): void;
113
+
114
+ export { type HMRClientOptions, type HMRHandler, type HMRMessage, type HMRUpdate, accept, createHMRClient, dispose, getHMRClient };
@@ -0,0 +1,114 @@
1
+ /**
2
+ * @lytjs/hmr - Type definitions
3
+ */
4
+ interface HMRClientOptions {
5
+ /** WebSocket URL */
6
+ url?: string;
7
+ /** 是否自动连接 */
8
+ autoConnect?: boolean;
9
+ }
10
+ interface HMRMessage {
11
+ /** 消息类型 */
12
+ type: 'connected' | 'update' | 'full-reload' | 'custom';
13
+ /** 数据 */
14
+ data?: any;
15
+ }
16
+ interface HMRUpdate {
17
+ /** 模块路径 */
18
+ path: string;
19
+ /** 更新时间戳 */
20
+ timestamp: number;
21
+ /** 是否需要保留状态 */
22
+ preserveState?: boolean;
23
+ }
24
+ interface HMRHandler {
25
+ /** 接受更新 */
26
+ accept?: (update: HMRUpdate) => void;
27
+ /** 处理错误 */
28
+ error?: (error: Error) => void;
29
+ /** 清理旧模块 */
30
+ dispose?: () => void;
31
+ }
32
+
33
+ /**
34
+ * @lytjs/hmr - LytJS 热模块替换
35
+ *
36
+ * 提供热模块替换的核心功能
37
+ */
38
+
39
+ /**
40
+ * HMR 客户端类
41
+ */
42
+ declare class HMRClient {
43
+ private options;
44
+ private ws;
45
+ private handlers;
46
+ private isConnected;
47
+ constructor(options?: HMRClientOptions);
48
+ /**
49
+ * 连接到 HMR 服务器
50
+ */
51
+ connect(): void;
52
+ /**
53
+ * 处理消息
54
+ */
55
+ private handleMessage;
56
+ /**
57
+ * 处理模块更新
58
+ */
59
+ private handleUpdate;
60
+ /**
61
+ * 处理完全重新加载
62
+ */
63
+ private handleFullReload;
64
+ /**
65
+ * 注册模块处理程序
66
+ */
67
+ register(path: string, handler: HMRHandler): void;
68
+ /**
69
+ * 注销模块处理程序
70
+ */
71
+ unregister(path: string): void;
72
+ /**
73
+ * 发送消息到服务器
74
+ */
75
+ send(message: HMRMessage): void;
76
+ /**
77
+ * 分发事件
78
+ */
79
+ private dispatch;
80
+ /**
81
+ * 断开连接
82
+ */
83
+ disconnect(): void;
84
+ }
85
+ /**
86
+ * 创建 HMR 客户端
87
+ *
88
+ * @param options - 客户端选项
89
+ * @returns HMR 客户端实例
90
+ */
91
+ declare function createHMRClient(options?: HMRClientOptions): HMRClient;
92
+ /**
93
+ * 获取全局 HMR 客户端
94
+ *
95
+ * @param options - 客户端选项(首次调用时使用)
96
+ * @returns HMR 客户端实例
97
+ */
98
+ declare function getHMRClient(options?: HMRClientOptions): HMRClient;
99
+ /**
100
+ * HMR 模块接受函数
101
+ *
102
+ * @param path - 模块路径
103
+ * @param handler - 处理程序
104
+ */
105
+ declare function accept(path: string, handler: (update: HMRUpdate) => void): void;
106
+ /**
107
+ * HMR 模块清理函数
108
+ *
109
+ * @param path - 模块路径
110
+ * @param handler - 清理函数
111
+ */
112
+ declare function dispose(path: string, handler: () => void): void;
113
+
114
+ export { type HMRClientOptions, type HMRHandler, type HMRMessage, type HMRUpdate, accept, createHMRClient, dispose, getHMRClient };
package/dist/index.mjs ADDED
@@ -0,0 +1,151 @@
1
+ // src/index.ts
2
+ var HMRClient = class {
3
+ constructor(options = {}) {
4
+ this.ws = null;
5
+ this.handlers = /* @__PURE__ */ new Map();
6
+ this.isConnected = false;
7
+ this.options = {
8
+ url: options.url || "ws://localhost:5173",
9
+ autoConnect: options.autoConnect !== false
10
+ };
11
+ if (this.options.autoConnect) {
12
+ this.connect();
13
+ }
14
+ }
15
+ /**
16
+ * 连接到 HMR 服务器
17
+ */
18
+ connect() {
19
+ if (this.ws) {
20
+ this.ws.close();
21
+ }
22
+ console.log("[HMR] Connecting to", this.options.url);
23
+ try {
24
+ this.ws = new WebSocket(this.options.url);
25
+ this.ws.onopen = () => {
26
+ this.isConnected = true;
27
+ console.log("[HMR] Connected");
28
+ this.dispatch({ type: "connected" });
29
+ };
30
+ this.ws.onmessage = (event) => {
31
+ this.handleMessage(event.data);
32
+ };
33
+ this.ws.onclose = () => {
34
+ this.isConnected = false;
35
+ console.log("[HMR] Disconnected, reconnecting in 2s...");
36
+ setTimeout(() => this.connect(), 2e3);
37
+ };
38
+ this.ws.onerror = (error) => {
39
+ console.error("[HMR] WebSocket error", error);
40
+ };
41
+ } catch (error) {
42
+ console.error("[HMR] Connection failed", error);
43
+ setTimeout(() => this.connect(), 2e3);
44
+ }
45
+ }
46
+ /**
47
+ * 处理消息
48
+ */
49
+ handleMessage(data) {
50
+ try {
51
+ const message = JSON.parse(data);
52
+ console.log("[HMR] Received message:", message.type);
53
+ switch (message.type) {
54
+ case "update":
55
+ this.handleUpdate(message.data);
56
+ break;
57
+ case "full-reload":
58
+ this.handleFullReload();
59
+ break;
60
+ default:
61
+ this.dispatch(message);
62
+ break;
63
+ }
64
+ } catch (error) {
65
+ console.error("[HMR] Failed to parse message", error);
66
+ }
67
+ }
68
+ /**
69
+ * 处理模块更新
70
+ */
71
+ handleUpdate(update) {
72
+ const handler = this.handlers.get(update.path);
73
+ if (handler?.accept) {
74
+ console.log("[HMR] Accepting update for", update.path);
75
+ handler.accept(update);
76
+ } else {
77
+ console.log("[HMR] No handler for", update.path, ", reloading");
78
+ this.handleFullReload();
79
+ }
80
+ }
81
+ /**
82
+ * 处理完全重新加载
83
+ */
84
+ handleFullReload() {
85
+ console.log("[HMR] Full reload requested");
86
+ window.location.reload();
87
+ }
88
+ /**
89
+ * 注册模块处理程序
90
+ */
91
+ register(path, handler) {
92
+ this.handlers.set(path, handler);
93
+ }
94
+ /**
95
+ * 注销模块处理程序
96
+ */
97
+ unregister(path) {
98
+ this.handlers.delete(path);
99
+ }
100
+ /**
101
+ * 发送消息到服务器
102
+ */
103
+ send(message) {
104
+ if (this.ws && this.isConnected) {
105
+ this.ws.send(JSON.stringify(message));
106
+ }
107
+ }
108
+ /**
109
+ * 分发事件
110
+ */
111
+ dispatch(message) {
112
+ const event = new CustomEvent("lytjs:hmr", {
113
+ detail: message
114
+ });
115
+ window.dispatchEvent(event);
116
+ }
117
+ /**
118
+ * 断开连接
119
+ */
120
+ disconnect() {
121
+ if (this.ws) {
122
+ this.ws.close();
123
+ this.ws = null;
124
+ }
125
+ }
126
+ };
127
+ function createHMRClient(options = {}) {
128
+ return new HMRClient(options);
129
+ }
130
+ var globalClient = null;
131
+ function getHMRClient(options = {}) {
132
+ if (!globalClient) {
133
+ globalClient = createHMRClient(options);
134
+ }
135
+ return globalClient;
136
+ }
137
+ function accept(path, handler) {
138
+ const client = getHMRClient();
139
+ client.register(path, { accept: handler });
140
+ }
141
+ function dispose(path, handler) {
142
+ const client = getHMRClient();
143
+ const existing = client["handlers"].get(path) || {};
144
+ client.register(path, { ...existing, dispose: handler });
145
+ }
146
+ export {
147
+ accept,
148
+ createHMRClient,
149
+ dispose,
150
+ getHMRClient
151
+ };
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@lytjs/hmr",
3
+ "version": "6.5.0",
4
+ "description": "LytJS Hot Module Replacement support",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.mjs",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.mjs",
13
+ "require": "./dist/index.cjs"
14
+ },
15
+ "./package.json": "./package.json"
16
+ },
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "sideEffects": false,
21
+ "scripts": {
22
+ "build": "tsup",
23
+ "dev": "tsup --watch",
24
+ "test": "vitest run",
25
+ "type-check": "tsc --noEmit",
26
+ "lint": "eslint \"src/**/*.ts\"",
27
+ "clean": "rm -rf dist"
28
+ },
29
+ "dependencies": {},
30
+ "devDependencies": {
31
+ "tsup": "^8.0.0",
32
+ "typescript": "^5.4.0",
33
+ "vitest": "^3.0.0"
34
+ },
35
+ "license": "MIT",
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "https://gitee.com/lytjs/lytjs.git",
39
+ "directory": "packages/ecosystem/packages/hmr"
40
+ },
41
+ "keywords": [
42
+ "lytjs",
43
+ "hmr",
44
+ "hot-module-replacement"
45
+ ]
46
+ }