Migration Plan: From Git Submodules to Monorepo
๐ฏ Goal
Transform the LARC project from a git submodules architecture to a modern monorepo that's easier to develop and maintain.๐ Current State Analysis
Current Architecture (Submodules - PAINFUL ๐ซ)
larc/ (meta repo)
โโโ core/ (submodule โ @larcjs/core)
โโโ ui/ (submodule โ @larcjs/ui)
โโโ apps/ (submodule)
โ โโโ components/ (nested submodule)
โ โโโ core/ (nested submodule)
โโโ site/ (submodule)
โโโ examples/ (submodule)
โโโ devtools/ (submodule)
โโโ cli/ (submodule?)
โโโ playground/ (submodule?)
โโโ react-adapter/ (submodule?)
โโโ components-types/ (submodule)
โโโ core-types/ (submodule)
Problems:
- 8+ separate git repos to manage
- Detached HEAD confusion
- Complex push/pull workflows
- Nested submodules (apps has its own submodules!)
- Hard for new contributors
- Difficult to make atomic changes across packages
๐จ Proposed Architecture (Monorepo - EASY ๐)
Option A: npm/yarn/pnpm Workspaces (RECOMMENDED)
larc/ (single git repo)
โโโ package.json (workspace root)
โโโ packages/
โ โโโ core/ (@larcjs/core)
โ โโโ components/ (@larcjs/ui)
โ โโโ components-types/ (@larcjs/ui-types)
โ โโโ core-types/ (@larcjs/core-types)
โ โโโ react-adapter/ (@larcjs/react-adapter)
โ โโโ cli/ (@larcjs/cli)
โ โโโ devtools/ (@larcjs/devtools)
โโโ apps/
โ โโโ contact-manager/
โ โโโ invoice/
โ โโโ markdown-notes/
โ โโโ data-browser/
โโโ examples/
โโโ site/ (documentation site)
โโโ playground/
Workflow:
# One clone
git clone https://github.com/larcjs/larc.git
# One install (links all packages automatically)
npm install
# Work across packages easily
cd packages/core
# edit core...
cd ../components
# edit components that depend on core...
# Both changes tested together!
# One commit for atomic changes
git add packages/core packages/ui
git commit -m "Add feature across core and components"
git push
๐ Migration Steps
Phase 1: Assessment (1 hour)
- [ ] Identify which "submodules" are actually published packages vs. just code organization
- [ ] List cross-package dependencies
- [ ] Document current release process
Phase 2: Preparation (2 hours)
- [ ] Create new branch
feature/monorepo-migration - [ ] Backup current state
- [ ] Create root
package.jsonwith workspaces config - [ ] Set up build tooling (turborepo, nx, or just npm workspaces)
Phase 3: Migration (4-6 hours)
- [ ] Copy submodule code into packages/ directory
- [ ] Remove .git directories from former submodules
- [ ] Update package.json dependencies to use workspace protocol
- [ ] Update import paths if needed
- [ ] Test that everything builds and runs
- [ ] Update CI/CD pipelines
Phase 4: Cleanup (1 hour)
- [ ] Archive old submodule repos (keep for history)
- [ ] Update documentation
- [ ] Update contributor guide
- [ ] Test deployment
๐ Detailed Implementation
1. Root package.json
{
"name": "larc-monorepo",
"version": "1.0.0",
"private": true,
"workspaces": [
"packages/*"
],
"scripts": {
"build": "npm run build --workspaces",
"test": "npm run test --workspaces",
"dev": "npm run dev --workspaces --if-present",
"clean": "npm run clean --workspaces --if-present"
},
"devDependencies": {
"turbo": "^2.0.0", // Optional: faster builds
"changesets": "^2.0.0" // Optional: version management
}
}
2. Update Package Dependencies
Before (submodules):// packages/ui/package.json
{
"peerDependencies": {
"@larcjs/core": "^1.1.0"
}
}
After (monorepo):
// packages/ui/package.json
{
"dependencies": {
"@larcjs/core": "workspace:*"
},
"peerDependencies": {
"@larcjs/core": "^1.1.0" // Still needed for external consumers
}
}
3. Migration Script
Create migrate-to-monorepo.sh:
#!/bin/bash
set -e
echo "๐ Starting migration to monorepo..."
# Create packages directory
mkdir -p packages
# Move submodules to packages (preserving git history)
PACKAGES="core ui components-types core-types react-adapter cli devtools"
for pkg in $PACKAGES; do
echo "๐ฆ Migrating $pkg..."
# Get the actual directory name (ui โ components)
if [ "$pkg" = "ui" ]; then
SOURCE="ui"
DEST="packages/ui"
else
SOURCE="$pkg"
DEST="packages/$pkg"
fi
# Move with history preservation
if [ -d "$SOURCE" ]; then
# Remove submodule connection
git submodule deinit -f "$SOURCE" 2>/dev/null || true
rm -rf ".git/modules/$SOURCE" 2>/dev/null || true
# Move the directory
mv "$SOURCE" "$DEST"
# Remove .git reference if it exists
rm -f "$DEST/.git"
fi
done
# Move apps, examples, site to root (not in packages)
echo "๐ Organizing other directories..."
# These are already in place
# Remove submodule config
rm -f .gitmodules
echo "โ
Physical migration complete!"
echo "๐ Next steps:"
echo " 1. Update package.json files with workspace: protocol"
echo " 2. Run npm install"
echo " 3. Test builds"
echo " 4. Update documentation"
๐ Alternative: Keep Some Repos Separate
If you want to keep @larcjs/core and @larcjs/ui in separate repos (for independent versioning), use a hybrid approach:
Hybrid Option: Monorepo + External Packages
larc/ (monorepo)
โโโ packages/
โ โโโ cli/
โ โโโ react-adapter/
โ โโโ devtools/
โโโ apps/ (links to @larcjs/core, @larcjs/ui via npm)
โโโ examples/ (links via npm)
โโโ site/ (links via npm)
# Separate repos:
github.com/larcjs/core โ published as @larcjs/core
github.com/larcjs/components โ published as @larcjs/ui
Development workflow:
# For core development
npm link @larcjs/core
npm link @larcjs/ui
# Or use npm install git+https://...
This is simpler but loses the "atomic commits" benefit.
๐ฆ Tooling Options
Option 1: Plain npm Workspaces (Simple)
Pros: Built-in, no extra tools Cons: Slower builds, basic features// package.json
{
"workspaces": ["packages/*"]
}
Option 2: pnpm Workspaces (Better)
Pros: Faster, better disk usage, workspace protocol Cons: Need to install pnpm# pnpm-workspace.yaml
packages:
- 'packages/*'
Option 3: Turborepo (Best for scaling)
Pros: Caching, parallel builds, remote caching Cons: Extra complexity// turbo.json
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**"]
}
}
}
Option 4: Nx (Most features)
Pros: Everything + graph viz, generators Cons: Steeper learning curve๐ฏ Recommended Path for LARC
Recommendation: pnpm Workspaces + Changesets
Why:- Fast, reliable package manager (pnpm)
- Excellent monorepo support
- Simple workspace protocol
- Changesets for version/changelog management
- Not too complex, not too simple
# 1. Install pnpm
npm install -g pnpm
# 2. Create pnpm-workspace.yaml
cat > pnpm-workspace.yaml << EOF
packages:
- 'packages/*'
EOF
# 3. Create root package.json
cat > package.json << EOF
{
"name": "larc",
"private": true,
"scripts": {
"build": "pnpm -r build",
"test": "pnpm -r test",
"dev": "pnpm -r --parallel dev"
},
"devDependencies": {
"@changesets/cli": "^2.27.0"
}
}
EOF
# 4. Migrate packages
./migrate-to-monorepo.sh
# 5. Update package.json dependencies
# Change peerDependencies to: "@larcjs/core": "workspace:*"
# 6. Install
pnpm install
# 7. Test
pnpm build
pnpm test
๐ Comparison: Before vs After
| Aspect | Submodules | Monorepo |
|--------|-----------|----------|
| Clone | git clone --recurse-submodules | git clone |
| Update | git pull && git submodule update --init --recursive --remote | git pull |
| Work on package | cd pkg && git checkout main && git pull | cd packages/pkg |
| Cross-package change | 3+ commits, 3+ pushes | 1 commit, 1 push |
| Dependencies | Manual, error-prone | Automatic via workspaces |
| Build | Manual coordination | Orchestrated |
| New contributor | 30min + docs | 5min |
| CI/CD | Complex, multiple triggers | Simple, single trigger |
๐จ Migration Risks & Mitigation
Risk 1: Lost Git History
Mitigation: Use git subtree or keep old repos as archives# Preserve history when moving
git subtree add --prefix=packages/core https://github.com/larcjs/core.git main
Risk 2: Breaking External Dependents
Mitigation: Keep old repos as "release mirrors"- Keep github.com/larcjs/core for npm registry
- Monorepo becomes source of truth
- Auto-push releases to old repos
Risk 3: Large Repo Size
Mitigation: Use git partial clone for CIgit clone --filter=blob:none --depth=1
Risk 4: Team Resistance
Mitigation:- Pilot with small team first
- Document benefits clearly
- Provide scripts/aliases for common tasks
๐ฌ Quick Start: Try It Out (Non-Destructive)
Want to try before committing? Test on a copy:
# 1. Clone into new directory
git clone https://github.com/larcjs/larc.git larc-monorepo-test
cd larc-monorepo-test
# 2. Create test branch
git checkout -b test-monorepo
# 3. Run migration script (I'll create this)
./test-monorepo.sh
# 4. Try the workflow
pnpm install
pnpm build
# Make changes...
git add .
git commit -m "Test change"
# 5. If you like it, do it for real. If not, delete the directory.
๐ Resources
- pnpm Workspaces
- Turborepo
- Changesets
- Monorepo.tools
- Why Google Stores Billions of Lines of Code in a Single Repository
โ Success Criteria
Migration is successful when:
- [ ]
git clone+pnpm install+pnpm buildworks - [ ] All tests pass
- [ ] Can edit core and see changes in components immediately
- [ ] Single commit can update multiple packages
- [ ] New contributors can get started in < 10 minutes
- [ ] CI/CD is simpler and faster
- [ ] Team is happier ๐
๐ค Still Want Submodules?
If you must keep submodules for some reason, at least use git-subrepo instead of git submodule:
- No detached HEAD
- Simpler workflow
- Better for contributors
Created: 2025-12-06