@bsg-export/worker 1.0.8

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,102 @@
1
+ # @bsg-export/worker
2
+
3
+ [![npm](https://img.shields.io/npm/v/@bsg-export/worker)](https://www.npmjs.com/package/@bsg-export/worker)
4
+
5
+ > [belobog-stellar-grid](https://github.com/kurisu994/belobog-stellar-grid) 的 Web Worker 导出封装
6
+
7
+ ## 简介
8
+
9
+ 将 CSV/XLSX 文件生成移至 Worker 线程,主线程不阻塞。适用于大数据量导出(10000+ 行)。
10
+
11
+ ## 安装
12
+
13
+ ```bash
14
+ npm install @bsg-export/worker belobog-stellar-grid
15
+ # 或
16
+ pnpm add @bsg-export/worker belobog-stellar-grid
17
+ ```
18
+
19
+ **前置依赖**:`belobog-stellar-grid >= 1.0.0`
20
+
21
+ ## 使用方式
22
+
23
+ ### 方式 1:ExportWorker 类(通用)
24
+
25
+ ```typescript
26
+ import { ExportWorker } from '@bsg-export/worker';
27
+
28
+ // Vite
29
+ import ExportWorkerScript from '@bsg-export/worker/worker?worker';
30
+ const worker = new ExportWorker(new ExportWorkerScript());
31
+
32
+ // Webpack 5
33
+ const w = new Worker(new URL('@bsg-export/worker/worker', import.meta.url), { type: 'module' });
34
+ const worker = new ExportWorker(w);
35
+
36
+ // 初始化
37
+ await worker.init();
38
+
39
+ // 导出数据(Worker 生成 → 主线程下载)
40
+ await worker.exportData(
41
+ [{ name: '张三', age: 28 }],
42
+ {
43
+ columns: [{ title: '姓名', key: 'name' }, { title: '年龄', key: 'age' }],
44
+ filename: '用户.xlsx',
45
+ format: 1,
46
+ },
47
+ { onProgress: (p) => console.log(`${p}%`) }
48
+ );
49
+
50
+ // 仅生成字节
51
+ const bytes = await worker.generateBytes(data, options);
52
+
53
+ // 销毁
54
+ worker.terminate();
55
+ ```
56
+
57
+ ### 方式 2:React Hook
58
+
59
+ ```tsx
60
+ import { useWorkerExporter } from '@bsg-export/react';
61
+ import ExportWorkerScript from '@bsg-export/worker/worker?worker';
62
+
63
+ const { initialized, loading, progress, exportData } = useWorkerExporter(
64
+ () => new ExportWorkerScript()
65
+ );
66
+ ```
67
+
68
+ ### 方式 3:Vue 3 Composable
69
+
70
+ ```vue
71
+ <script setup>
72
+ import { useWorkerExporter } from '@bsg-export/vue';
73
+ import ExportWorkerScript from '@bsg-export/worker/worker?worker';
74
+
75
+ const { initialized, loading, progress, exportData } = useWorkerExporter(
76
+ () => new ExportWorkerScript()
77
+ );
78
+ </script>
79
+ ```
80
+
81
+ ## API
82
+
83
+ ### `ExportWorker`
84
+
85
+ | 方法 | 说明 |
86
+ |------|------|
87
+ | `init()` | 初始化 Worker 中的 WASM 模块 |
88
+ | `exportData(data, options?, workerOptions?)` | 生成文件并触发下载 |
89
+ | `generateBytes(data, options?, workerOptions?)` | 仅生成文件字节 |
90
+ | `terminate()` | 销毁 Worker |
91
+ | `initialized` | `boolean` — WASM 是否初始化完成 |
92
+
93
+ ### Worker 创建方式
94
+
95
+ | 构建工具 | 创建方式 |
96
+ |---------|---------|
97
+ | **Vite** | `import W from '@bsg-export/worker/worker?worker'` |
98
+ | **Webpack 5** | `new Worker(new URL('@bsg-export/worker/worker', import.meta.url))` |
99
+
100
+ ## 许可证
101
+
102
+ MIT OR Apache-2.0
@@ -0,0 +1,110 @@
1
+ /**
2
+ * ExportWorker - Web Worker 导出管理器
3
+ *
4
+ * 将导出计算移至 Worker 线程,彻底避免主线程阻塞。
5
+ * 适用于大数据量场景下的 CSV/XLSX 导出。
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { ExportWorker } from '@bsg-export/worker';
10
+ * import MyWorker from './my-worker?worker';
11
+ *
12
+ * const worker = new ExportWorker(new MyWorker());
13
+ * await worker.init();
14
+ *
15
+ * // 导出数据(在 Worker 线程中生成,主线程触发下载)
16
+ * await worker.exportData(
17
+ * [{ name: '张三', age: 28 }],
18
+ * {
19
+ * columns: [{ title: '姓名', key: 'name' }, { title: '年龄', key: 'age' }],
20
+ * filename: '用户.xlsx',
21
+ * format: 1, // ExportFormat.Xlsx
22
+ * }
23
+ * );
24
+ *
25
+ * // 使用完毕后销毁
26
+ * worker.terminate();
27
+ * ```
28
+ */
29
+ import type { ExportDataOptions, DataRow, ProgressCallback } from '@bsg-export/types';
30
+ /** ExportWorker 配置选项 */
31
+ export interface ExportWorkerOptions {
32
+ /** 进度回调函数 */
33
+ onProgress?: ProgressCallback;
34
+ }
35
+ /**
36
+ * Web Worker 导出管理器
37
+ *
38
+ * 封装 Worker 生命周期管理、消息协议、文件下载触发。
39
+ */
40
+ export declare class ExportWorker {
41
+ private worker;
42
+ private pending;
43
+ private _initialized;
44
+ /**
45
+ * 创建 ExportWorker 实例
46
+ *
47
+ * @param worker - Worker 实例,由用户根据构建工具自行创建
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * // Vite
52
+ * import MyWorker from './export-worker?worker';
53
+ * const ew = new ExportWorker(new MyWorker());
54
+ *
55
+ * // Webpack 5
56
+ * const worker = new Worker(new URL('./export-worker', import.meta.url));
57
+ * const ew = new ExportWorker(worker);
58
+ * ```
59
+ */
60
+ constructor(worker: Worker);
61
+ /** WASM 是否已初始化完成 */
62
+ get initialized(): boolean;
63
+ /**
64
+ * 初始化 Worker 中的 WASM 模块
65
+ *
66
+ * 必须在调用 exportData 之前调用。
67
+ */
68
+ init(): Promise<void>;
69
+ /**
70
+ * 在 Worker 中生成文件并触发下载
71
+ *
72
+ * @param data - 导出数据(二维数组或对象数组)
73
+ * @param options - 导出选项(同 ExportDataOptions,但 progressCallback 通过 onProgress 传入)
74
+ * @param workerOptions - Worker 特有选项
75
+ *
76
+ * @returns Promise,导出完成时 resolve
77
+ * @throws 导出失败时 reject
78
+ */
79
+ exportData(data: DataRow[], options?: Omit<ExportDataOptions, 'progressCallback'>, workerOptions?: ExportWorkerOptions): Promise<void>;
80
+ /**
81
+ * 仅生成文件字节(不触发下载)
82
+ *
83
+ * 适用于需要自定义下载逻辑或进一步处理文件内容的场景。
84
+ *
85
+ * @param data - 导出数据
86
+ * @param options - 导出选项
87
+ * @param workerOptions - Worker 特有选项
88
+ *
89
+ * @returns 文件字节的 Uint8Array
90
+ */
91
+ generateBytes(data: DataRow[], options?: Omit<ExportDataOptions, 'progressCallback'>, workerOptions?: ExportWorkerOptions): Promise<Uint8Array>;
92
+ /**
93
+ * 销毁 Worker
94
+ */
95
+ terminate(): void;
96
+ /**
97
+ * 处理 Worker 消息
98
+ */
99
+ private handleMessage;
100
+ /**
101
+ * 处理 Worker 错误
102
+ */
103
+ private handleError;
104
+ /**
105
+ * 在主线程触发文件下载
106
+ */
107
+ private downloadFile;
108
+ }
109
+ export type { ExportWorkerOptions as WorkerOptions };
110
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EACV,iBAAiB,EACjB,OAAO,EACP,gBAAgB,EACjB,MAAM,mBAAmB,CAAC;AAmB3B,wBAAwB;AACxB,MAAM,WAAW,mBAAmB;IAClC,aAAa;IACb,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B;AAiBD;;;;GAIG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAqC;IACpD,OAAO,CAAC,YAAY,CAAS;IAE7B;;;;;;;;;;;;;;;OAeG;gBACS,MAAM,EAAE,MAAM;IAM1B,oBAAoB;IACpB,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED;;;;OAIG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAmB3B;;;;;;;;;OASG;IACG,UAAU,CACd,IAAI,EAAE,OAAO,EAAE,EACf,OAAO,CAAC,EAAE,IAAI,CAAC,iBAAiB,EAAE,kBAAkB,CAAC,EACrD,aAAa,CAAC,EAAE,mBAAmB,GAClC,OAAO,CAAC,IAAI,CAAC;IAgBhB;;;;;;;;;;OAUG;IACG,aAAa,CACjB,IAAI,EAAE,OAAO,EAAE,EACf,OAAO,CAAC,EAAE,IAAI,CAAC,iBAAiB,EAAE,kBAAkB,CAAC,EACrD,aAAa,CAAC,EAAE,mBAAmB,GAClC,OAAO,CAAC,UAAU,CAAC;IA6BtB;;OAEG;IACH,SAAS,IAAI,IAAI;IAWjB;;OAEG;IACH,OAAO,CAAC,aAAa;IAkCrB;;OAEG;IACH,OAAO,CAAC,WAAW;IASnB;;OAEG;IACH,OAAO,CAAC,YAAY;CAoCrB;AAED,YAAY,EAAE,mBAAmB,IAAI,aAAa,EAAE,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,227 @@
1
+ /**
2
+ * ExportWorker - Web Worker 导出管理器
3
+ *
4
+ * 将导出计算移至 Worker 线程,彻底避免主线程阻塞。
5
+ * 适用于大数据量场景下的 CSV/XLSX 导出。
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { ExportWorker } from '@bsg-export/worker';
10
+ * import MyWorker from './my-worker?worker';
11
+ *
12
+ * const worker = new ExportWorker(new MyWorker());
13
+ * await worker.init();
14
+ *
15
+ * // 导出数据(在 Worker 线程中生成,主线程触发下载)
16
+ * await worker.exportData(
17
+ * [{ name: '张三', age: 28 }],
18
+ * {
19
+ * columns: [{ title: '姓名', key: 'name' }, { title: '年龄', key: 'age' }],
20
+ * filename: '用户.xlsx',
21
+ * format: 1, // ExportFormat.Xlsx
22
+ * }
23
+ * );
24
+ *
25
+ * // 使用完毕后销毁
26
+ * worker.terminate();
27
+ * ```
28
+ */
29
+ /**
30
+ * 生成唯一请求 ID
31
+ */
32
+ let requestCounter = 0;
33
+ function generateId() {
34
+ return `req_${++requestCounter}_${Date.now()}`;
35
+ }
36
+ /**
37
+ * Web Worker 导出管理器
38
+ *
39
+ * 封装 Worker 生命周期管理、消息协议、文件下载触发。
40
+ */
41
+ export class ExportWorker {
42
+ /**
43
+ * 创建 ExportWorker 实例
44
+ *
45
+ * @param worker - Worker 实例,由用户根据构建工具自行创建
46
+ *
47
+ * @example
48
+ * ```typescript
49
+ * // Vite
50
+ * import MyWorker from './export-worker?worker';
51
+ * const ew = new ExportWorker(new MyWorker());
52
+ *
53
+ * // Webpack 5
54
+ * const worker = new Worker(new URL('./export-worker', import.meta.url));
55
+ * const ew = new ExportWorker(worker);
56
+ * ```
57
+ */
58
+ constructor(worker) {
59
+ this.pending = new Map();
60
+ this._initialized = false;
61
+ this.worker = worker;
62
+ this.worker.addEventListener('message', this.handleMessage.bind(this));
63
+ this.worker.addEventListener('error', this.handleError.bind(this));
64
+ }
65
+ /** WASM 是否已初始化完成 */
66
+ get initialized() {
67
+ return this._initialized;
68
+ }
69
+ /**
70
+ * 初始化 Worker 中的 WASM 模块
71
+ *
72
+ * 必须在调用 exportData 之前调用。
73
+ */
74
+ async init() {
75
+ if (this._initialized)
76
+ return;
77
+ return new Promise((resolve, reject) => {
78
+ const id = generateId();
79
+ this.pending.set(id, {
80
+ resolve: () => {
81
+ this._initialized = true;
82
+ resolve();
83
+ },
84
+ reject,
85
+ });
86
+ const request = { type: 'init', id };
87
+ this.worker.postMessage(request);
88
+ });
89
+ }
90
+ /**
91
+ * 在 Worker 中生成文件并触发下载
92
+ *
93
+ * @param data - 导出数据(二维数组或对象数组)
94
+ * @param options - 导出选项(同 ExportDataOptions,但 progressCallback 通过 onProgress 传入)
95
+ * @param workerOptions - Worker 特有选项
96
+ *
97
+ * @returns Promise,导出完成时 resolve
98
+ * @throws 导出失败时 reject
99
+ */
100
+ async exportData(data, options, workerOptions) {
101
+ if (!this._initialized) {
102
+ throw new Error('ExportWorker 未初始化,请先调用 init()');
103
+ }
104
+ const bytes = await this.generateBytes(data, options, workerOptions);
105
+ // 在主线程触发下载
106
+ this.downloadFile(bytes, options?.filename, options?.format, options?.withBom);
107
+ }
108
+ /**
109
+ * 仅生成文件字节(不触发下载)
110
+ *
111
+ * 适用于需要自定义下载逻辑或进一步处理文件内容的场景。
112
+ *
113
+ * @param data - 导出数据
114
+ * @param options - 导出选项
115
+ * @param workerOptions - Worker 特有选项
116
+ *
117
+ * @returns 文件字节的 Uint8Array
118
+ */
119
+ async generateBytes(data, options, workerOptions) {
120
+ if (!this._initialized) {
121
+ throw new Error('ExportWorker 未初始化,请先调用 init()');
122
+ }
123
+ const buffer = await new Promise((resolve, reject) => {
124
+ const id = generateId();
125
+ this.pending.set(id, {
126
+ resolve,
127
+ reject,
128
+ onProgress: workerOptions?.onProgress,
129
+ });
130
+ // Worker 中不传 progressCallback(它不可序列化),
131
+ // Worker 会自动注入 postMessage 版的进度回调
132
+ const { ...safeOptions } = options ?? {};
133
+ const request = {
134
+ type: 'generate',
135
+ id,
136
+ data,
137
+ options: safeOptions,
138
+ };
139
+ this.worker.postMessage(request);
140
+ });
141
+ return new Uint8Array(buffer);
142
+ }
143
+ /**
144
+ * 销毁 Worker
145
+ */
146
+ terminate() {
147
+ // 拒绝所有待处理的请求
148
+ for (const [, pending] of this.pending) {
149
+ pending.reject(new Error('Worker 已被销毁'));
150
+ }
151
+ this.pending.clear();
152
+ this.worker.terminate();
153
+ this._initialized = false;
154
+ }
155
+ /**
156
+ * 处理 Worker 消息
157
+ */
158
+ handleMessage(event) {
159
+ const { type, id, bytes, message, progress } = event.data;
160
+ const pending = this.pending.get(id);
161
+ if (!pending)
162
+ return;
163
+ switch (type) {
164
+ case 'ready':
165
+ // init 成功
166
+ this.pending.delete(id);
167
+ pending.resolve(new ArrayBuffer(0));
168
+ break;
169
+ case 'result':
170
+ // 生成成功
171
+ this.pending.delete(id);
172
+ pending.resolve(bytes);
173
+ break;
174
+ case 'error':
175
+ // 出错
176
+ this.pending.delete(id);
177
+ pending.reject(new Error(message ?? '未知错误'));
178
+ break;
179
+ case 'progress':
180
+ // 进度报告
181
+ if (pending.onProgress && progress !== undefined) {
182
+ pending.onProgress(progress);
183
+ }
184
+ break;
185
+ }
186
+ }
187
+ /**
188
+ * 处理 Worker 错误
189
+ */
190
+ handleError(event) {
191
+ // 拒绝所有待处理的请求
192
+ const error = new Error(`Worker 错误: ${event.message}`);
193
+ for (const [id, pending] of this.pending) {
194
+ pending.reject(error);
195
+ this.pending.delete(id);
196
+ }
197
+ }
198
+ /**
199
+ * 在主线程触发文件下载
200
+ */
201
+ downloadFile(data, filename, format, withBom) {
202
+ // 确定 MIME 类型和文件扩展名
203
+ const isXlsx = format === 1;
204
+ const mimeType = isXlsx
205
+ ? 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
206
+ : 'text/csv;charset=utf-8';
207
+ const defaultExt = isXlsx ? 'xlsx' : 'csv';
208
+ const defaultFilename = `export.${defaultExt}`;
209
+ let finalFilename = filename ?? defaultFilename;
210
+ // 确保文件有正确的扩展名
211
+ if (!finalFilename.endsWith(`.${defaultExt}`)) {
212
+ finalFilename = `${finalFilename}.${defaultExt}`;
213
+ }
214
+ // CSV 且需要 BOM 时,在字节前面加上 BOM(Worker 中 generate_data_bytes 已处理)
215
+ // 这里无需额外处理,因为 withBom 选项已传给 Worker
216
+ // 创建 Blob 并触发下载
217
+ const blob = new Blob([data.buffer], { type: mimeType });
218
+ const url = URL.createObjectURL(blob);
219
+ const anchor = document.createElement('a');
220
+ anchor.href = url;
221
+ anchor.download = finalFilename;
222
+ anchor.click();
223
+ // 延迟 10 秒后释放 Blob URL
224
+ setTimeout(() => URL.revokeObjectURL(url), 10000);
225
+ }
226
+ }
227
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Web Worker 脚本 - 在 Worker 线程中加载 WASM 并执行导出
3
+ *
4
+ * 此脚本运行在 Web Worker 环境中,负责:
5
+ * 1. 初始化 WASM 模块
6
+ * 2. 接收主线程发来的导出请求
7
+ * 3. 调用 generate_data_bytes 生成文件字节
8
+ * 4. 通过 Transferable 将字节传回主线程
9
+ */
10
+ /** 声明 belobog-stellar-grid 模块类型 */
11
+ declare module 'belobog-stellar-grid' {
12
+ function generate_data_bytes(data: unknown, options?: unknown): Uint8Array;
13
+ export default function init(): Promise<void>;
14
+ }
15
+ /** Worker 接收的消息类型 */
16
+ interface WorkerRequest {
17
+ /** 消息类型 */
18
+ type: 'init' | 'generate';
19
+ /** 请求唯一标识 */
20
+ id: string;
21
+ /** WASM 模块路径(init 时使用) */
22
+ wasmUrl?: string;
23
+ /** 导出数据(generate 时使用) */
24
+ data?: unknown;
25
+ /** 导出选项(generate 时使用) */
26
+ options?: Record<string, unknown>;
27
+ }
28
+ /** Worker 发送的消息类型 */
29
+ interface WorkerResponse {
30
+ /** 消息类型 */
31
+ type: 'ready' | 'result' | 'error' | 'progress';
32
+ /** 对应的请求标识 */
33
+ id: string;
34
+ /** 生成的文件字节(result 时) */
35
+ bytes?: ArrayBuffer;
36
+ /** 错误信息(error 时) */
37
+ message?: string;
38
+ /** 进度值 0-100(progress 时) */
39
+ progress?: number;
40
+ }
41
+ /** WASM 模块实例 */
42
+ declare let wasmModule: typeof import('belobog-stellar-grid') | null;
43
+ /**
44
+ * 初始化 WASM 模块
45
+ */
46
+ declare function initWasm(id: string): Promise<void>;
47
+ /**
48
+ * 生成导出文件字节
49
+ */
50
+ declare function generateBytes(id: string, data: unknown, options?: Record<string, unknown>): void;
51
+ //# sourceMappingURL=worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,mCAAmC;AACnC,OAAO,QAAQ,sBAAsB,CAAC;IACpC,SAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC;IAClF,MAAM,CAAC,OAAO,UAAU,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/C;AAED,qBAAqB;AACrB,UAAU,aAAa;IACrB,WAAW;IACX,IAAI,EAAE,MAAM,GAAG,UAAU,CAAC;IAC1B,aAAa;IACb,EAAE,EAAE,MAAM,CAAC;IACX,0BAA0B;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yBAAyB;IACzB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,yBAAyB;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,qBAAqB;AACrB,UAAU,cAAc;IACtB,WAAW;IACX,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAC;IAChD,cAAc;IACd,EAAE,EAAE,MAAM,CAAC;IACX,wBAAwB;IACxB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,oBAAoB;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4BAA4B;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,gBAAgB;AAChB,QAAA,IAAI,UAAU,EAAE,cAAc,sBAAsB,CAAC,GAAG,IAAW,CAAC;AAEpE;;GAEG;AACH,iBAAe,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBjD;AAED;;GAEG;AACH,iBAAS,aAAa,CACpB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,OAAO,EACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,IAAI,CAkCN"}
package/dist/worker.js ADDED
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ /**
3
+ * Web Worker 脚本 - 在 Worker 线程中加载 WASM 并执行导出
4
+ *
5
+ * 此脚本运行在 Web Worker 环境中,负责:
6
+ * 1. 初始化 WASM 模块
7
+ * 2. 接收主线程发来的导出请求
8
+ * 3. 调用 generate_data_bytes 生成文件字节
9
+ * 4. 通过 Transferable 将字节传回主线程
10
+ */
11
+ /// <reference lib="webworker" />
12
+ /** WASM 模块实例 */
13
+ let wasmModule = null;
14
+ /**
15
+ * 初始化 WASM 模块
16
+ */
17
+ async function initWasm(id) {
18
+ try {
19
+ const mod = await import('belobog-stellar-grid');
20
+ await mod.default();
21
+ wasmModule = mod;
22
+ const response = { type: 'ready', id };
23
+ self.postMessage(response);
24
+ }
25
+ catch (err) {
26
+ const response = {
27
+ type: 'error',
28
+ id,
29
+ message: `WASM 初始化失败: ${err instanceof Error ? err.message : String(err)}`,
30
+ };
31
+ self.postMessage(response);
32
+ }
33
+ }
34
+ /**
35
+ * 生成导出文件字节
36
+ */
37
+ function generateBytes(id, data, options) {
38
+ if (!wasmModule) {
39
+ const response = {
40
+ type: 'error',
41
+ id,
42
+ message: 'WASM 模块未初始化,请先发送 init 消息',
43
+ };
44
+ self.postMessage(response);
45
+ return;
46
+ }
47
+ try {
48
+ // 构建选项,注入进度回调(通过 postMessage 传回主线程)
49
+ const workerOptions = { ...options };
50
+ workerOptions.progressCallback = (progress) => {
51
+ const response = { type: 'progress', id, progress };
52
+ self.postMessage(response);
53
+ };
54
+ // 调用 WASM 的 generate_data_bytes
55
+ const bytes = wasmModule.generate_data_bytes(data, workerOptions);
56
+ // 通过 Transferable 传输字节,避免拷贝
57
+ const buffer = bytes.buffer;
58
+ const response = { type: 'result', id, bytes: buffer };
59
+ self.postMessage(response, [buffer]);
60
+ }
61
+ catch (err) {
62
+ const response = {
63
+ type: 'error',
64
+ id,
65
+ message: `导出失败: ${err instanceof Error ? err.message : String(err)}`,
66
+ };
67
+ self.postMessage(response);
68
+ }
69
+ }
70
+ /**
71
+ * 监听主线程消息
72
+ */
73
+ self.addEventListener('message', (event) => {
74
+ const { type, id, data, options } = event.data;
75
+ switch (type) {
76
+ case 'init':
77
+ initWasm(id);
78
+ break;
79
+ case 'generate':
80
+ generateBytes(id, data, options);
81
+ break;
82
+ default:
83
+ self.postMessage({
84
+ type: 'error',
85
+ id,
86
+ message: `未知的消息类型: ${type}`,
87
+ });
88
+ }
89
+ });
90
+ //# sourceMappingURL=worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.js","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@bsg-export/worker",
3
+ "version": "1.0.8",
4
+ "description": "belobog-stellar-grid 的 Web Worker 封装,将导出计算移至 Worker 线程",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./worker": {
14
+ "types": "./dist/worker.d.ts",
15
+ "import": "./dist/worker.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "scripts": {
22
+ "build": "tsc",
23
+ "typecheck": "tsc --noEmit"
24
+ },
25
+ "keywords": [
26
+ "belobog",
27
+ "stellar-grid",
28
+ "worker",
29
+ "web-worker",
30
+ "export",
31
+ "table"
32
+ ],
33
+ "author": "Kurisu <makise_kurisuu@outlook.jp>",
34
+ "license": "MIT OR Apache-2.0",
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "https://github.com/kurisu994/belobog-stellar-grid",
38
+ "directory": "packages/worker"
39
+ },
40
+ "peerDependencies": {
41
+ "belobog-stellar-grid": ">=1.0.0"
42
+ },
43
+ "dependencies": {
44
+ "@bsg-export/types": "file:../types"
45
+ },
46
+ "devDependencies": {
47
+ "typescript": "^5.9.3"
48
+ }
49
+ }