UNPKG

@tanstack/table-core

Version:

Headless UI for building powerful tables & datagrids for TS/JS.

99 lines (97 loc) 3.54 kB
import { makeObjectMap } from "../utils.js"; import { constructTable } from "../core/table/constructTable.js"; import { storeReactivityBindings } from "../store-reactivity-bindings.js"; import { serializeRowModel } from "./serializeRowModel.js"; //#region src/worker/initTableWorker.ts function capitalize(stage) { return stage.charAt(0).toUpperCase() + stage.slice(1); } /** Flatten column-group defs to leaf defs (mirrors core's id resolution). */ function flattenColumnDefs(defs) { return defs.flatMap((def) => def.columns ? flattenColumnDefs(def.columns) : [def]); } /** * Runs a headless "shadow table" inside a dedicated Web Worker. * * Call this from a user-authored worker entry file, passing the same columns * and processing features used on the main thread. The shadow table runs the * real table-core row model pipeline (real fns, real Row objects) off the * main thread and posts back one payload per stage the main thread requested: * a transferable index permutation for flat results, a serialized row tree * (with eagerly computed aggregates) when grouping produces synthetic rows. * * Everything passed here must be thread-portable: `accessorKey` columns or * accessors defined in a shared module, and fns from registries or shared * modules (no closures over app state). * * @example * ```ts * // table.worker.ts * import { initTableWorker } from '@tanstack/table-core/experimental-worker-plugin' * import { columns, sharedFeatures } from './tableConfig' * * initTableWorker({ features: sharedFeatures, columns }) * ``` */ function initTableWorker(config) { let table; let dataVersion = 0; let coreIndexById = makeObjectMap(); let aggregateColumnIds = []; let lastSentModels = {}; self.onmessage = (event) => { const message = event.data; if (message.type === "data") { dataVersion = message.dataVersion; lastSentModels = {}; if (!table) { table = constructTable({ ...config, features: { coreReactivityFeature: storeReactivityBindings(), ...config.features }, data: message.data }); aggregateColumnIds = flattenColumnDefs(config.columns).filter((def) => def.aggregationFn != null || def.aggregatedCell != null).map((def) => def.id ?? (def.accessorKey === void 0 ? void 0 : String(def.accessorKey).replaceAll(".", "_"))).filter((id) => id != null); } else table.setOptions((prev) => ({ ...prev, data: message.data })); const coreFlatRows = table.getCoreRowModel().flatRows; coreIndexById = makeObjectMap(); for (let i = 0; i < coreFlatRows.length; i++) coreIndexById[coreFlatRows[i].id] = i; return; } if (!table) return; const start = performance.now(); table._reactivity.batch(() => { for (const [key, value] of Object.entries(message.state)) { const baseAtom = table.baseAtoms[key]; if (baseAtom && value !== void 0) baseAtom.set(value); } }); const stages = {}; const transfer = []; for (const stage of message.stages) { if (!config.features[`${stage}RowModel`]) continue; const model = table[`get${capitalize(stage)}RowModel`](); if (lastSentModels[stage] === model) { stages[stage] = { kind: "unchanged" }; continue; } lastSentModels[stage] = model; stages[stage] = serializeRowModel(model, coreIndexById, aggregateColumnIds, transfer); } const response = { type: "result", requestId: message.requestId, dataVersion, stages, computeMs: performance.now() - start }; postMessage(response, { transfer }); }; } //#endregion export { initTableWorker };