Skip to content

Package Structure

This document describes the structure and organization of GridSheet packages.

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 overview
@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)

@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.

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.

Packageexternal (Vite)peerDependencies
@gridsheet/enginedayjs— (dayjs is a direct dependency)
@gridsheet/web@gridsheet/engine, dayjs— (@gridsheet/engine is a direct dependency)
@gridsheet/react-corereact, react-dom, @gridsheet/web, dayjsreact, react-dom, dayjs (@gridsheet/web is in dependencies)
@gridsheet/preact-corepreact, @gridsheet/web, dayjspreact, dayjs (@gridsheet/web is in dependencies)
@gridsheet/functions@gridsheet/web, dayjs@gridsheet/web, dayjs
@gridsheet/react-devreact, react-dom, @gridsheet/webreact, react-dom, @gridsheet/web

Note: @gridsheet/web is listed in dependencies (not peerDependencies) for react-core and preact-core because they always require it. For functions and react-dev, it is a peerDependency because @gridsheet/web is expected to be provided by the framework package (react-core or preact-core) that the user already has installed.

  • @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]

  • @gridsheet/functions: Extended formula functions library. Provides allFunctions and createSpellbook. Use useSpellbook from @gridsheet/react-core/spellbook for the React hook version.
  • @gridsheet/react-dev: Development utilities for React.

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.

{
"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"
}

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
  • Core Updates: Both react-core and preact-core bump together
  • Wrapper Updates: Only vue-core increment 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