Package Structure
This document describes the structure and organization of GridSheet packages.
Monorepo Overview
Section titled “Monorepo Overview”GridSheet is organized as a monorepo using pnpm workspaces:
gridsheet/├── packages/│ ├── engine/ # Headless model + formula engine (framework/DOM-free)│ ├── web/ # Web/DOM rendering layer (built on engine; re-exports it)│ ├── react-core/ # React implementation (components, hooks, store)│ ├── preact-core/ # Preact implementation (same codebase, different build target)│ ├── react-dev/ # Development utilities for React│ ├── functions/ # Extended formula functions (@gridsheet/functions)│ ├── vue-core/ # Vue.js implementation (wrapper around preact-core)│ ├── docs/ # Documentation site│ └── storybook/ # Component examples and testing├── e2e/ # Playwright end-to-end tests├── package.json # Root package configuration├── tsconfig.json # Root TypeScript configuration└── README.md # Project overviewDependency Graph
Section titled “Dependency Graph”@gridsheet/engine ← Headless: model + formula engine (no React/DOM) └── @gridsheet/web ← Web/DOM layer; re-exports engine (dep: engine) ├── @gridsheet/react-core ← React components, hooks, store (dep: web) │ └── @gridsheet/react-dev (peerDep: web) ├── @gridsheet/preact-core ← Preact build via alias (dep: web) │ └── @gridsheet/vue-core (dep: preact-core) └── @gridsheet/functions ← Formula definitions (peerDep: web)Why @gridsheet/engine exists
Section titled “Why @gridsheet/engine exists”@gridsheet/functions uses classes like Sheet, Registry, and BaseFunction. Previously, functions depended on @gridsheet/react-core, which forced Preact users to install react-core as well. This resulted in two separate copies of these classes in the bundle, causing instanceof checks to fail (e.g. SUM returning 0).
By keeping the framework-agnostic model + formula engine in @gridsheet/engine, every package resolves the same class instances regardless of the framework. @gridsheet/web layers the browser-specific DOM/render helpers on top (and re-exports the engine API), so the framework bindings depend on @gridsheet/web while the engine stays usable headlessly on its own.
External and peerDependencies
Section titled “External and peerDependencies”When a package marks a dependency as external in its Vite config, the import statement (e.g. from "@gridsheet/web") is preserved in the built output rather than bundled. This means the dependency must exist in the user’s node_modules at runtime.
peerDependencies declares this requirement to the package manager. Without it, npm/pnpm would not warn users when the external dependency is missing or has an incompatible version. Therefore, external and peerDependencies are always paired together.
| Package | external (Vite) | peerDependencies |
|---|---|---|
@gridsheet/engine | dayjs | — (dayjs is a direct dependency) |
@gridsheet/web | @gridsheet/engine, dayjs | — (@gridsheet/engine is a direct dependency) |
@gridsheet/react-core | react, react-dom, @gridsheet/web, dayjs | react, react-dom, dayjs (@gridsheet/web is in dependencies) |
@gridsheet/preact-core | preact, @gridsheet/web, dayjs | preact, dayjs (@gridsheet/web is in dependencies) |
@gridsheet/functions | @gridsheet/web, dayjs | @gridsheet/web, dayjs |
@gridsheet/react-dev | react, react-dom, @gridsheet/web | react, react-dom, @gridsheet/web |
Note:
@gridsheet/webis listed in dependencies (not peerDependencies) forreact-coreandpreact-corebecause they always require it. Forfunctionsandreact-dev, it is a peerDependency because@gridsheet/webis expected to be provided by the framework package (react-coreorpreact-core) that the user already has installed.
Versioning Strategy
Section titled “Versioning Strategy”Core Packages
Section titled “Core Packages”- @gridsheet/engine: Headless, framework-agnostic model + formula engine (Sheet, Registry, formula, policy, coords, spatial, etc.) — no React/DOM.
- @gridsheet/web: Web/DOM rendering layer built on the engine (DOM, input, popup, virtualization, styles); re-exports the engine API.
- @gridsheet/react-core: React components, hooks, and store
- @gridsheet/preact-core: Preact build (same codebase via react→preact/compat alias)
These core packages always maintain identical versions following semantic versioning: MAJOR.MINOR.PATCH[-PRERELEASE]
Extended Packages
Section titled “Extended Packages”- @gridsheet/functions: Extended formula functions library. Provides
allFunctionsandcreateSpellbook. UseuseSpellbookfrom@gridsheet/react-core/spellbookfor the React hook version. - @gridsheet/react-dev: Development utilities for React.
Wrapper Packages
Section titled “Wrapper Packages”The Vue implementation is a wrapper around the preact-core:
- @gridsheet/vue-core: Vue.js wrapper around preact-core
When only the wrapper layer is updated, this package uses the format: MAJOR.MINOR.PATCH-X where X starts from 0 and increments as integers.
Version Examples
Section titled “Version Examples”{ "name": "@gridsheet/react-core", "version": "2.0.0-rc.2"}
{ "name": "@gridsheet/preact-core", "version": "2.0.0-rc.2"}
{ "name": "@gridsheet/vue-core", "version": "2.0.0-rc.2-0"}Git Tagging Strategy
Section titled “Git Tagging Strategy”All packages in the monorepo use the following git tag format upon release:
{package-name}/{version}For example:
@gridsheet/react-core/2.0.0-rc.2@gridsheet/vue-core/2.0.0-rc.2-0
Version Bumping Rules
Section titled “Version Bumping Rules”- Core Updates: Both
react-coreandpreact-corebump together - Wrapper Updates: Only
vue-coreincrement the suffix (0, 1, 2, …) - Breaking Changes: All packages bump major version
- New Features: All packages bump minor version
- Bug Fixes: All packages bump patch version