Skill Index

growi/

monorepo-overview

community[skill]

GROWI monorepo structure, workspace organization, and architectural principles. Auto-invoked for all GROWI development work.

$/plugin install growi

details

GROWI Monorepo Overview

GROWI is a team collaboration wiki platform built as a monorepo using pnpm workspace + Turborepo.

Monorepo Structure

growi/
├── apps/                    # Applications
│   ├── app/                # Main GROWI application (Next.js + Express + MongoDB)
│   ├── pdf-converter/      # PDF conversion microservice (Ts.ED + Puppeteer)
│   └── slackbot-proxy/     # Slack integration proxy (Ts.ED + TypeORM + MySQL)
├── packages/               # Shared libraries
│   ├── core/              # Core utilities and shared logic
│   ├── core-styles/       # Common styles (SCSS)
│   ├── editor/            # Markdown editor components
│   ├── ui/                # UI component library
│   ├── pluginkit/         # Plugin framework
│   ├── slack/             # Slack integration utilities
│   ├── presentation/      # Presentation mode
│   ├── pdf-converter-client/ # PDF converter client library
│   └── remark-*/          # Markdown plugins (remark-lsx, remark-drawio, etc.)
└── Configuration files
    ├── pnpm-workspace.yaml
    ├── turbo.json
    ├── package.json
    └── .changeset/

Workspace Management

pnpm Workspace

All packages are managed via pnpm workspace. Package references use the workspace: protocol:

{
  "dependencies": {
    "@growi/core": "workspace:^",
    "@growi/ui": "workspace:^"
  }
}

Turborepo Orchestration

Turborepo handles task orchestration with caching and parallelization:

# Run tasks across all workspaces
turbo run dev
turbo run test
turbo run lint
turbo run build

# Filter to specific package
turbo run test --filter @growi/app
turbo run lint --filter @growi/core

Build Order Management

Build dependencies in this monorepo are not declared with dependsOn: ["^build"] (the automatic workspace-dependency mode). Instead, they are declared explicitly — either in the root turbo.json for legacy entries, or in per-package turbo.json files for newer packages.

When to update: whenever a package gains a new workspace dependency on another buildable package (one that produces a dist/), declare the build-order dependency explicitly. Without it, Turborepo may build in the wrong order, causing missing dist/ files or type errors.

Pattern — per-package turbo.json (preferred for new dependencies):

// packages/my-package/turbo.json
{
  "extends": ["//"],
  "tasks": {
    "build": { "dependsOn": ["@growi/some-dep#build"] },
    "dev":   { "dependsOn": ["@growi/some-dep#dev"] }
  }
}
  • "extends": ["//"] inherits all root task definitions; only add the extra dependsOn
  • Keep root turbo.json clean — package-level overrides live with the package that owns the dependency
  • For packages with multiple tasks (watch, lint, test), mirror the dependency in each relevant task

Existing examples:

  • packages/slack/turbo.jsonbuild/dev depend on @growi/logger
  • packages/remark-attachment-refs/turbo.json — all tasks depend on @growi/core, @growi/logger, @growi/remark-growi-directive, @growi/ui
  • Root turbo.json@growi/ui#build depends on @growi/core#build (pre-dates the per-package pattern)

Architectural Principles

1. Feature-Based Architecture (Recommended)

All packages should prefer feature-based organization:

{package}/src/
├── features/              # Feature modules
│   ├── {feature-name}/
│   │   ├── index.ts      # Main export
│   │   ├── interfaces/   # TypeScript types
│   │   ├── server/       # Server-side logic (if applicable)
│   │   ├── client/       # Client-side logic (if applicable)
│   │   └── utils/        # Shared utilities

Benefits:

  • Clear boundaries between features
  • Easy to locate related code
  • Facilitates gradual migration from legacy structure

2. Server-Client Separation

For full-stack packages (like apps/app), separate server and client logic:

  • Server code: Node.js runtime, database access, API routes
  • Client code: Browser runtime, React components, UI state

This enables better code splitting and prevents server-only code from being bundled into client.

3. Shared Libraries in packages/

Common code should be extracted to packages/:

  • core: Domain hub (see below)
  • ui: Reusable React components
  • editor: Markdown editor
  • pluginkit: Plugin system framework

@growi/core — Domain & Utilities Hub

@growi/core is the foundational shared package depended on by all other packages (10 consumers). Its responsibilities:

  • Domain type definitions — Single source of truth for cross-package interfaces (IPage, IUser, IRevision, Ref<T>, HasObjectId, etc.)
  • Cross-cutting utilities — Pure functions for page path validation, ObjectId checks, serialization (e.g., serializeUserSecurely())
  • System constants — File types, plugin configs, scope enums
  • Global type augmentations — Runtime/polyfill type declarations visible to all consumers (e.g., RegExp.escape() via declare global in index.ts)

Key patterns:

  1. Shared types and global augmentations go in @growi/core — Not duplicated per-package. declare global in index.ts propagates to all consumers through the module graph.
  2. Subpath exports for granular imports@growi/core/dist/utils/page-path-utils instead of barrel imports from root.
  3. Minimal runtime dependencies — Only bson-objectid; ~70% types. Safe to import from both server and client contexts.
  4. Server-specific interfaces are namespaced — Under interfaces/server/.
  5. Dual format (ESM + CJS) — Built via Vite with preserveModules: true and vite-plugin-dts (copyDtsFiles: true).

Version Management with Changeset

GROWI uses Changesets for version management and release notes:

# Add a changeset (after making changes)
npx changeset

# Version bump (generates CHANGELOGs and updates versions)
pnpm run version-subpackages

# Publish packages to npm (for @growi/core, @growi/pluginkit)
pnpm run release-subpackages

Changeset Workflow

  1. Make code changes
  2. Run npx changeset and describe the change
  3. Commit both code and .changeset/*.md file
  4. On release, run pnpm run version-subpackages
  5. Changesets automatically updates CHANGELOG.md and package.json versions

Version Schemes

  • Main app (apps/app): Manual versioning with RC prereleases
    • pnpm run version:patch, pnpm run version:prerelease
  • Shared libraries (packages/core, packages/pluginkit): Changeset-managed
  • Microservices (apps/pdf-converter, apps/slackbot-proxy): Independent versioning

Package Categories

Applications (apps/)

PackageDescriptionTech Stack
@growi/appMain wiki applicationNext.js (Pages Router), Express, MongoDB, Jotai, SWR
@growi/pdf-converterPDF export serviceTs.ED, Puppeteer
@growi/slackbot-proxySlack bot proxyTs.ED, TypeORM, MySQL

Core Libraries (packages/)

PackageDescriptionPublished to npm
@growi/coreCore utilities
@growi/pluginkitPlugin framework
@growi/uiUI components❌ (internal)
@growi/editorMarkdown editor❌ (internal)
@growi/core-stylesCommon styles❌ (internal)

Development Workflow

Initial Setup

# Install dependencies for all packages
pnpm install

# Bootstrap (install + build dependencies)
turbo run bootstrap

Daily Development

# Start all dev servers (apps/app + dependencies)
turbo run dev

# Run a specific test file (from package directory)
pnpm vitest run yjs.integ

# Run ALL tests / lint for a package
turbo run test --filter @growi/app
turbo run lint --filter @growi/core

Cross-Package Development

When modifying shared libraries (packages/*), ensure dependent apps reflect changes:

  1. Make changes to packages/core
  2. Turborepo automatically detects changes and rebuilds dependents
  3. Test in apps/app to verify

Key Configuration Files

  • pnpm-workspace.yaml: Defines workspace packages
  • turbo.json: Turborepo pipeline configuration
  • .changeset/config.json: Changeset configuration
  • tsconfig.base.json: Base TypeScript config for all packages
  • vitest.workspace.mts: Vitest workspace config
  • biome.json: Biome linter/formatter config

Design Principles Summary

  1. Feature Isolation: Use feature-based architecture for new code
  2. Server-Client Separation: Keep server and client code separate
  3. Shared Libraries: Extract common code to packages/
  4. Type-Driven Development: Define interfaces before implementation
  5. Progressive Enhancement: Migrate legacy code gradually
  6. Version Control: Use Changesets for release management

technical

github
growilabs/growi
stars
1447
license
MIT
contributors
100
last commit
2026-04-21T07:00:54Z
file
.claude/skills/monorepo-overview/SKILL.md

related